JSON from plist path SUBROUTINE

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()
3 Likes