All Projects → RobTrew → prelude-jxa

RobTrew / prelude-jxa

Licence: MIT License
Generic functions for macOS and iOS scripting in Javascript – function names as in Hoogle

Programming Languages

javascript
184084 projects - #8 most used programming language
HTML
75241 projects

Projects that are alternatives of or similar to prelude-jxa

node-jxa
Use your favorite node.js modules (and JS editor) for your Javascript OSX automation scripts
Stars: ✭ 52 (+1.96%)
Mutual labels:  jxa
automating-macOS-with-JXA-presentation
Slides & sample code from the "Automating macOS with Javascript for Automation" talk, given at the MelbJS meetup
Stars: ✭ 40 (-21.57%)
Mutual labels:  jxa
AppleScriptive
Functional AppleScripts operating out of Keyboard Maestro, Alfred and Automator to optimise productivity.
Stars: ✭ 44 (-13.73%)
Mutual labels:  jxa
dotfiles
Dotfiles. Mac and *nix. Handy scripts, configurations for bash, zsh, git, asdf, Sublime Text, Karabiner-Elements, BetterTouchTool and more.
Stars: ✭ 15 (-70.59%)
Mutual labels:  jxa
is-jxa
Check if your code is running in a JXA environment
Stars: ✭ 28 (-45.1%)
Mutual labels:  jxa
sublime-applescript
AppleScript command completions, build system and useful snippets. Supports editing binary scripts
Stars: ✭ 50 (-1.96%)
Mutual labels:  jxa
Jxa Cookbook
Cookbook for JavaScript for Automation in Mac OS X Yosemite
Stars: ✭ 2,603 (+5003.92%)
Mutual labels:  jxa

prelude-jxa

Generic functions for:

  • macOS scripting with JavaScript for Automation
  • iOS scripting in JavaScript, with apps like the excellent 1Writer, and @agiletortoise's Drafts.

Details:

  • Function names are as in Hoogle.
  • The 400+ functions in jsPrelude.js are generic and cross-platform (macOS, iOS etc),
  • The 20+ functions in jxaSystemIO.js are specific to macOS.

For the purposes of sketching and testing a script,
the JavaScriptCore interpreter used on macOS and iOS is fast enough to allow for import of the whole of the jsPrelude.js file and, in the case of macOS, the jxaSystemIO.js file as well.

(c. 500 generic and file-system functions in total)

Display a menu of functions to copy to the clipboard

Menu of functions

(() => {
    'use strict';
    
    // Display a menu of functions to select and copy.
    // Rob Trew @2020

    ObjC.import('AppKit')

    // ---------------------- MAIN ----------------------
    const main = () => {
        const inner = () => {
            const
                fpFolder = '~/prelude-jxa',
                menuJSONFile = 'jsPreludeMenu.json';
            return either(
                alert('JavaScript functions')
            )(
                // Copied to clipboard and returned.
                x => (
                    copyText(x),
                    x
                )
            )(
                bindLR(
                    readFileLR(
                        combine(fpFolder)(menuJSONFile)
                    )
                )(
                    json => bindLR(
                        jsonParseLR(json)
                    )(
                        dict => bindLR(
                            showMenuLR(true)(
                                'Functions'
                            )(Object.keys(dict))
                        )(
                            ks => Right(
                                ks.map(k => dict[k])
                                .join('\n\n\n')
                            )
                        )
                    )
                )
            )
        };

        // 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
                );
            };

        // copyText :: String -> IO String
        const copyText = s => {
            const pb = $.NSPasteboard.generalPasteboard;
            return (
                pb.clearContents,
                pb.setStringForType(
                    $(s),
                    $.NSPasteboardTypeString
                ),
                s
            );
        };

        return inner();
    };

    // ---------------- JS PRELUDE - JXA ----------------

    // readFileLR :: FilePath -> Either String IO String
    const readFileLR = fp => {
        const
            e = $(),
            ns = $.NSString
            .stringWithContentsOfFileEncodingError(
                $(fp).stringByStandardizingPath,
                $.NSUTF8StringEncoding,
                e
            );
        return ns.isNil() ? (
            Left(ObjC.unwrap(e.localizedDescription))
        ) : Right(ObjC.unwrap(ns));
    };


    // ------------------- JS PRELUDE -------------------

    // 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 = m =>
        mf => undefined !== m.Left ? (
            m
        ) : mf(m.Right);

    // combine (</>) :: FilePath -> FilePath -> FilePath
    const combine = fp =>
        // Two paths combined with a path separator. 
        // Just the second path if that starts 
        // with a path separator.
        fp1 => Boolean(fp) && Boolean(fp1) ? (
            '/' === fp1.slice(0, 1) ? (
                fp1
            ) : '/' === fp.slice(-1) ? (
                fp + fp1
            ) : fp + '/' + fp1
        ) : fp + fp1;

    // 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 => 'Either' === e.type ? (
            undefined !== e.Left ? (
                fl(e.Left)
            ) : fr(e.Right)
        ) : undefined;

    // 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})`
            );
        }
    };

    // showMenuLR :: Bool -> String -> [String] -> 
    // Either String [String]
    const showMenuLR = blnMult =>
        title => xs => 0 < xs.length ? (() => {
            const sa = Object.assign(
                Application('System Events'), {
                    includeStandardAdditions: true
                });
            sa.activate();
            const v = sa.chooseFromList(xs, {
                withTitle: title,
                withPrompt: 'Select' + (
                    blnMult ? (
                        ' one or more of ' +
                        xs.length.toString()
                    ) : ':'
                ),
                defaultItems: xs[0],
                okButtonName: 'OK',
                cancelButtonName: 'Cancel',
                multipleSelectionsAllowed: blnMult,
                emptySelectionAllowed: false
            });
            return Array.isArray(v) ? (
                Right(v)
            ) : Left('User cancelled ' + title + ' menu.');
        })() : Left(title + ': No items to choose from.');

    return main();
})();
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].