Names of All Applications Installed by the macOS Package Manager

Names of all installed applications.kmmacros (3.3 KB)


Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    ObjC.import("AppKit");

    // ----- MACOS LISTING OF INSTALLED APPLICATIONS -----

    // RobTrew @2022
    // Ver 0.01

    // main :: IO ()
    const main = () =>
        lines(
            Object.assign(
                Application.currentApplication(),
                {includeStandardAdditions: true}
            )
            .doShellScript("pkgutil --pkgs")
        )
        .flatMap(bundleID => {
            const
                fp = ObjC.unwrap(
                    $.NSWorkspace.sharedWorkspace
                    .URLForApplicationWithBundleIdentifier(
                        bundleID
                    )
                    .fileSystemRepresentation
                );

            return Boolean(fp) ? (
                [takeBaseName(fp)]
            ) : [];
        })
        .sort()
        .join("\n");


    // --------------------- GENERIC ---------------------

    // lines :: String -> [String]
    const lines = s =>
    // A list of strings derived from a single string
    // which is delimited by \n or by \r\n or \r.
        Boolean(s.length) ? (
            s.split(/\r\n|\n|\r/u)
        ) : [];


    // takeBaseName :: FilePath -> String
    const takeBaseName = fp =>
    // The filepath without any extension.
        ("" !== fp) ? (
            ("/" !== fp[fp.length - 1]) ? (() => {
                const fn = fp.split("/").slice(-1)[0];

                return fn.includes(".") ? (
                    fn.split(".").slice(0, -1)
                    .join(".")
                ) : fn;
            })() : ""
        ) : "";

    // MAIN ---
    return main();
})();
2 Likes

Or for a listing by case-insensitive sort:

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    ObjC.import("AppKit");

    // ----- MACOS LISTING OF INSTALLED APPLICATIONS -----

    // RobTrew @2022
    // Ver 0.02

    // main :: IO ()
    const main = () =>
        sortOn(s => s.toLocaleLowerCase())(
            lines(
                Object.assign(
                    Application.currentApplication(),
                    {includeStandardAdditions: true}
                )
                .doShellScript("pkgutil --pkgs")
            )
            .flatMap(bundleID => {
                const
                    fp = ObjC.unwrap(
                        $.NSWorkspace.sharedWorkspace
                        .URLForApplicationWithBundleIdentifier(
                            bundleID
                        )
                        .fileSystemRepresentation
                    );

                return Boolean(fp) ? (
                    [takeBaseName(fp)]
                ) : [];
            })
        )
        .join("\n");


    // --------------------- GENERIC ---------------------

    // comparing :: Ord a => (b -> a) -> b -> b -> Ordering
    const comparing = f =>
    // The ordering of f(x) and f(y) as a value
    // drawn from {-1, 0, 1}, representing {LT, EQ, GT}.
        x => y => {
            const
                a = f(x),
                b = f(y);

            return a < b ? -1 : (a > b ? 1 : 0);
        };


    // lines :: String -> [String]
    const lines = s =>
    // A list of strings derived from a single string
    // which is delimited by \n or by \r\n or \r.
        Boolean(s.length) ? (
            s.split(/\r\n|\n|\r/u)
        ) : [];


    // sortBy :: (a -> a -> Ordering) -> [a] -> [a]
    const sortBy = f =>
    // A copy of xs sorted by the comparator function f.
        xs => xs.slice()
        .sort((a, b) => f(a)(b));


    // sortOn :: Ord b => (a -> b) -> [a] -> [a]
    const sortOn = f =>
    // Equivalent to sortBy(comparing(f)), but with f(x)
    // evaluated only once for each x in xs.
    // ('Schwartzian' decorate-sort-undecorate).
        xs => sortBy(
            comparing(x => x[0])
        )(
            xs.map(x => [f(x), x])
        )
        .map(x => x[1]);


    // takeBaseName :: FilePath -> String
    const takeBaseName = fp =>
    // The filepath without any extension.
        ("" !== fp) ? (
            ("/" !== fp[fp.length - 1]) ? (() => {
                const fn = fp.split("/").slice(-1)[0];

                return fn.includes(".") ? (
                    fn.split(".").slice(0, -1)
                    .join(".")
                ) : fn;
            })() : ""
        ) : "";


    // MAIN ---
    return main();
})();

Seems only support Mac App Store Apps.

1 Like