{"id":13583086,"url":"https://github.com/RobTrew/prelude-jxa","last_synced_at":"2025-04-06T18:31:54.435Z","repository":{"id":38832788,"uuid":"138222271","full_name":"RobTrew/prelude-jxa","owner":"RobTrew","description":"Generic functions for macOS and iOS scripting in Javascript – function names as in Hoogle","archived":false,"fork":false,"pushed_at":"2025-03-17T22:02:16.000Z","size":7273,"stargazers_count":72,"open_issues_count":1,"forks_count":2,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-17T23:22:13.409Z","etag":null,"topics":["applescript","javascript","jxa","macos","prelude-based"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobTrew.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-21T21:12:23.000Z","updated_at":"2025-03-17T22:02:20.000Z","dependencies_parsed_at":"2023-12-22T16:03:01.559Z","dependency_job_id":"109fa78d-f840-488c-bf90-d2ea1b860658","html_url":"https://github.com/RobTrew/prelude-jxa","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTrew%2Fprelude-jxa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTrew%2Fprelude-jxa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTrew%2Fprelude-jxa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTrew%2Fprelude-jxa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobTrew","download_url":"https://codeload.github.com/RobTrew/prelude-jxa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247531045,"owners_count":20953884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["applescript","javascript","jxa","macos","prelude-based"],"created_at":"2024-08-01T15:03:14.878Z","updated_at":"2025-04-06T18:31:52.010Z","avatar_url":"https://github.com/RobTrew.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# prelude-jxa\nGeneric functions for:\n\n- **macOS** scripting with JavaScript for Automation\n- **iOS** scripting in JavaScript, with apps like the excellent [1Writer](http://1writerapp.com/), and @agiletortoise's Drafts.\n\n## Details:\n\n- Function names are as in [Hoogle](https://www.haskell.org/hoogle/?hoogle=concatMap).\n- The 400+ functions in [jsPrelude.js](https://github.com/RobTrew/prelude-jxa/blob/master/jsPrelude.js) are generic and cross-platform (macOS, iOS etc),\n- The 20+ functions in [jxaSystemIO.js](https://github.com/RobTrew/prelude-jxa/blob/master/jxaSystemIO.js) are specific to macOS.\n\nFor the purposes of sketching and testing  a script,  \nthe JavaScriptCore interpreter used on macOS and iOS is fast enough\nto allow for import of the whole of the [jsPrelude.js](https://github.com/RobTrew/prelude-jxa/blob/master/jsPrelude.js) file and,\nin the case of macOS, the [jxaSystemIO.js](https://github.com/RobTrew/prelude-jxa/blob/master/jxaSystemIO.js) file as well.\n\n(c. 500 generic and file-system functions in total)\n\n**Display a menu of functions to copy to the clipboard**\n\n ![Menu of functions](./functionMenu.png)\n\n```javascript\n(() =\u003e {\n    'use strict';\n    \n    // Display a menu of functions to select and copy.\n    // Rob Trew @2020\n\n    ObjC.import('AppKit')\n\n    // ---------------------- MAIN ----------------------\n    const main = () =\u003e {\n        const inner = () =\u003e {\n            const\n                fpFolder = '~/prelude-jxa',\n                menuJSONFile = 'jsPreludeMenu.json';\n            return either(\n                alert('JavaScript functions')\n            )(\n                // Copied to clipboard and returned.\n                x =\u003e (\n                    copyText(x),\n                    x\n                )\n            )(\n                bindLR(\n                    readFileLR(\n                        combine(fpFolder)(menuJSONFile)\n                    )\n                )(\n                    json =\u003e bindLR(\n                        jsonParseLR(json)\n                    )(\n                        dict =\u003e bindLR(\n                            showMenuLR(true)(\n                                'Functions'\n                            )(Object.keys(dict))\n                        )(\n                            ks =\u003e Right(\n                                ks.map(k =\u003e dict[k])\n                                .join('\\n\\n\\n')\n                            )\n                        )\n                    )\n                )\n            )\n        };\n\n        // alert :: String =\u003e String -\u003e IO String\n        const alert = title =\u003e\n            s =\u003e {\n                const sa = Object.assign(\n                    Application('System Events'), {\n                        includeStandardAdditions: true\n                    });\n                return (\n                    sa.activate(),\n                    sa.displayDialog(s, {\n                        withTitle: title,\n                        buttons: ['OK'],\n                        defaultButton: 'OK'\n                    }),\n                    s\n                );\n            };\n\n        // copyText :: String -\u003e IO String\n        const copyText = s =\u003e {\n            const pb = $.NSPasteboard.generalPasteboard;\n            return (\n                pb.clearContents,\n                pb.setStringForType(\n                    $(s),\n                    $.NSPasteboardTypeString\n                ),\n                s\n            );\n        };\n\n        return inner();\n    };\n\n    // ---------------- JS PRELUDE - JXA ----------------\n\n    // readFileLR :: FilePath -\u003e Either String IO String\n    const readFileLR = fp =\u003e {\n        const\n            e = $(),\n            ns = $.NSString\n            .stringWithContentsOfFileEncodingError(\n                $(fp).stringByStandardizingPath,\n                $.NSUTF8StringEncoding,\n                e\n            );\n        return ns.isNil() ? (\n            Left(ObjC.unwrap(e.localizedDescription))\n        ) : Right(ObjC.unwrap(ns));\n    };\n\n\n    // ------------------- JS PRELUDE -------------------\n\n    // Left :: a -\u003e Either a b\n    const Left = x =\u003e ({\n        type: 'Either',\n        Left: x\n    });\n\n    // Right :: b -\u003e Either a b\n    const Right = x =\u003e ({\n        type: 'Either',\n        Right: x\n    });\n\n    // bindLR (\u003e\u003e=) :: Either a -\u003e \n    // (a -\u003e Either b) -\u003e Either b\n    const bindLR = m =\u003e\n        mf =\u003e undefined !== m.Left ? (\n            m\n        ) : mf(m.Right);\n\n    // combine (\u003c/\u003e) :: FilePath -\u003e FilePath -\u003e FilePath\n    const combine = fp =\u003e\n        // Two paths combined with a path separator. \n        // Just the second path if that starts \n        // with a path separator.\n        fp1 =\u003e Boolean(fp) \u0026\u0026 Boolean(fp1) ? (\n            '/' === fp1.slice(0, 1) ? (\n                fp1\n            ) : '/' === fp.slice(-1) ? (\n                fp + fp1\n            ) : fp + '/' + fp1\n        ) : fp + fp1;\n\n    // either :: (a -\u003e c) -\u003e (b -\u003e c) -\u003e Either a b -\u003e c\n    const either = fl =\u003e\n        // Application of the function fl to the\n        // contents of any Left value in e, or\n        // the application of fr to its Right value.\n        fr =\u003e e =\u003e 'Either' === e.type ? (\n            undefined !== e.Left ? (\n                fl(e.Left)\n            ) : fr(e.Right)\n        ) : undefined;\n\n    // jsonParseLR :: String -\u003e Either String a\n    const jsonParseLR = s =\u003e {\n        try {\n            return Right(JSON.parse(s));\n        } catch (e) {\n            return Left(\n                `${e.message} (line:${e.line} col:${e.column})`\n            );\n        }\n    };\n\n    // showMenuLR :: Bool -\u003e String -\u003e [String] -\u003e \n    // Either String [String]\n    const showMenuLR = blnMult =\u003e\n        title =\u003e xs =\u003e 0 \u003c xs.length ? (() =\u003e {\n            const sa = Object.assign(\n                Application('System Events'), {\n                    includeStandardAdditions: true\n                });\n            sa.activate();\n            const v = sa.chooseFromList(xs, {\n                withTitle: title,\n                withPrompt: 'Select' + (\n                    blnMult ? (\n                        ' one or more of ' +\n                        xs.length.toString()\n                    ) : ':'\n                ),\n                defaultItems: xs[0],\n                okButtonName: 'OK',\n                cancelButtonName: 'Cancel',\n                multipleSelectionsAllowed: blnMult,\n                emptySelectionAllowed: false\n            });\n            return Array.isArray(v) ? (\n                Right(v)\n            ) : Left('User cancelled ' + title + ' menu.');\n        })() : Left(title + ': No items to choose from.');\n\n    return main();\n})();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobTrew%2Fprelude-jxa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRobTrew%2Fprelude-jxa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobTrew%2Fprelude-jxa/lists"}