Whereas passing KM8’s new dictionaries to scripts is very useful, the reverse traffic (building and returning dictionaries from scripts) seems likely to be less busy.
Not, however, impossible, though I think I would often use JSON.stringify() and JSON.parse() for that return direction.
Code snippets below for converting JavaScript dictionaries (Sierra onwards ES6) and Applescript records to Keyboard Maestro dictionaries:
JavaScript:
(() => {
'use strict';
// JS DICTIONARY -> KEYBOARD MAESTRO DICTIONARY --------------------------
// kmDictFromJSDict :: String -> Dict -> KM Dictionary
const kmDictFromJSDict = (strName, dct) => {
const kme = Application('Keyboard Maestro Engine');
return (
// Any existing KM dictionary of the given name cleared,
elem(strName, kme.dictionaries.name()) &&
kme.delete(kme.dictionaries.byName(strName)),
// and a new KM dictionary of the given name built
// from the JS dictionary
Object.keys(dct)
.reduce((a, k) => kmDictValueSet(strName, k, dct[k]), []),
kme.dictionaries.byName(strName)
);
};
// kmDictValueSet :: String -> String -> String -> KM ()
const kmDictValueSet = (strDict, strKey, strValue) =>
Application('Keyboard Maestro Engine')
.doScript(plistMay([{
MacroActionType: 'SetDictionaryValue',
Dictionary: strDict,
Key: strKey,
Value: strValue
}])
.just);
// GENERIC FUNCTIONS -----------------------------------------------------
// elem :: Eq a => a -> [a] -> Bool
const elem = (x, xs) => xs.indexOf(x) !== -1;
// plistMay :: JS Object -> Maybe Plist String
const plistMay = jso => {
var error = $();
const maybeString = $.NSString.alloc.initWithDataEncoding(
$.NSPropertyListSerialization
.dataWithPropertyListFormatOptionsError(
$(jso),
$.NSPropertyListXMLFormat_v1_0,
0,
error
),
$.NSUTF8StringEncoding
);
return Boolean(error.code) ? {
nothing: true,
msg: error.localizedDescription
} : {
nothing: false,
just: ObjC.unwrap(maybeString)
};
};
// TEST ------------------------------------------------------------------
return kmDictFromJSDict('Matriarchs', {
Sarah: 'Abraham',
Rebecca: 'Isaac',
Rachel: 'Jacob',
Leah: 'Jacob'
})
.dictionaryKeys();
})();
AppleScript:
use framework "Foundation"
-- APPLESCRIPT RECORD -> KEYBOARD MAESTRO DICTIONARY -------------------------
-- kmDictFromRecord :: String -> Record -> KM Dictionary
on kmDictFromRecord(strName, rec)
tell application "Keyboard Maestro Engine"
-- Any existing dictionary of the given name cleared,
if exists dictionary strName then delete dictionary strName
-- and new dictionary of the given name built
script kvAdded
-- kmDictValueSet :: String -> String -> String -> KM Dictionary
on kmDictValueSet(strDict, strKey, strValue)
tell application "Keyboard Maestro Engine"
do script (my recordAsPlist({{|MacroActionType|:¬
"SetDictionaryValue", |Dictionary|:¬
strDict, |Key|:strKey, |Value|:strValue}}))
dictionary strDict
end tell
end kmDictValueSet
on |λ|(a, k)
my kmDictValueSet(strName, k, just of keyValue(k, rec))
end |λ|
end script
my foldl(kvAdded, missing value, my keys(rec))
end tell
end kmDictFromRecord
-- TEST ----------------------------------------------------------------------
on run
tell application "Keyboard Maestro Engine"
dictionary keys of my kmDictFromRecord("Matriarchs", ¬
{Sarah:"Abraham", Rivka:"Isaac", Rachel:"Jacob", Leah:"Jacob"})
end tell
end run
-- GENERIC FUNCTIONS ---------------------------------------------------------
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
-- keys :: Record -> [String]
on keys(rec)
(current application's NSDictionary's dictionaryWithDictionary:rec)'s allKeys() as list
end keys
-- keyValue :: String -> Record -> Maybe a
on keyValue(strKey, rec)
set ca to current application
set v to (ca's NSDictionary's dictionaryWithDictionary:rec)'s objectForKey:strKey
if v is missing value then
{nothing:true}
else
{nothing:false, just:item 1 of ((ca's NSArray's arrayWithObject:v) as list)}
end if
end keyValue
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- recordAsPlist :: Record -> Maybe Plist String
on recordAsPlist(rec)
set ca to current application
(ca's NSString's alloc()'s ¬
initWithData:(ca's NSPropertyListSerialization's ¬
dataWithPropertyList:rec format:(ca's NSPropertyListXMLFormat_v1_0) ¬
options:0 |error|:(missing value)) encoding:(ca's NSUTF8StringEncoding)) as string
end recordAsPlist