Further example – obtaining the name of the first application in a Moom snapshot specified by title:
(as in Restore a Moom layout while hiding apps without windows in that layout )
JSON from plist path (TEST 2 -- First App in named Moom snapshot).kmmacros (7.9 KB)
Expand disclosure triangle to view JS source
// MAIN :: IO ()
const main = () =>
either(
alert("First app in snapshot")
)(
appName => appName
)(
bindLR(
jsonParseLR(kmvar.local_JSON)
)(
appNameForMoomshotTitleLR(
kmvar.local_Snapshot_Name
)
)
);
// ------------------- MOOM PLIST DATA -------------------
// appNameForMoomshotTitleLR :: String -> Dict -> Either String String
const appNameForMoomshotTitleLR = title =>
dict => {
const
snapshots = Object.keys(dict).flatMap(
k => k.startsWith("Custom Controls")
? dict[k].filter(
subDict => title === subDict.Title
)
: []
);
return bindLR(
0 < snapshots.length
? Right(snapshots[0])
: Left(`Snapshot not found: "${title}"`)
)(
firstAppNamedInShotLR
);
};
// firstAppNamedInShotLR :: Dict -> Either String String
function firstAppNamedInShotLR(snapDict) {
const
snapShot = snapDict.Snapshot, i = snapShot.findIndex(
shot => shot["Application Name"]
);
return -1 !== i
? Right(snapShot[i]["Application Name"])
: Left(`No application named in snapshot: "${title}"`);
}
// ------------------------- JXA -------------------------
// alert :: String => String -> IO String
const alert = title =>
s => {
const sa = Object.assign(
Application("System Events"), {
includeStandardAdditions: true
});
return (
sa.activate(),
sa.displayDialog(s, {
withTitle: title,
buttons: ["OK"],
defaultButton: "OK"
}),
s
);
};
// ----------------------- GENERIC -----------------------
// Left :: a -> Either a b
const Left = x => ({
type: "Either",
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: "Either",
Right: x
});
// bindLR (>>=) :: Either a ->
// (a -> Either b) -> Either b
const bindLR = lr =>
// Bind operator for the Either option type.
// If lr has a Left value then lr unchanged,
// otherwise the function mf applied to the
// Right value in lr.
mf => "Left" in lr
? lr
: mf(lr.Right);
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl =>
// Application of the function fl to the
// contents of any Left value in e, or
// the application of fr to its Right value.
fr => e => "Left" in e
? fl(e.Left)
: fr(e.Right);
// jsonParseLR :: String -> Either String a
const jsonParseLR = s => {
try {
return Right(JSON.parse(s));
} catch (e) {
return Left(
[
e.message,
`(line:${e.line} col:${e.column})`
].join("\n")
);
}
};
return main()
