From bf76910b8b8148480e1b60964ee8cf6de970b2e5 Mon Sep 17 00:00:00 2001 From: Richard Bidin Date: Sat, 4 Feb 2023 13:46:42 -0300 Subject: [PATCH] Improves plist parsing --- package-lock.json | 41 +++++++++++++++++++++++++++++++++++++++-- package.json | 1 + utils.js | 40 ++++++++++++++++++---------------------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d2a992..f1f4246 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dockhunt", - "version": "1.0.16", + "version": "1.0.17", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "dockhunt", - "version": "1.0.11", + "version": "1.0.17", "license": "ISC", "os": [ "darwin" @@ -15,6 +15,7 @@ "fs-extra": "^11.1.0", "node-fetch": "^3.3.0", "open": "^8.4.0", + "plist": "^3.0.6", "xml2js": "^0.4.23" }, "bin": { @@ -1513,6 +1514,26 @@ "node": ">=10" } }, + "node_modules/plist": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", + "integrity": "sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA==", + "dependencies": { + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/plist/node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "engines": { + "node": ">=8.0" + } + }, "node_modules/prebuild-install": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", @@ -3242,6 +3263,22 @@ } } }, + "plist": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", + "integrity": "sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA==", + "requires": { + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "dependencies": { + "xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==" + } + } + }, "prebuild-install": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", diff --git a/package.json b/package.json index eb3298f..48838b1 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "fs-extra": "^11.1.0", "node-fetch": "^3.3.0", "open": "^8.4.0", + "plist": "^3.0.6", "xml2js": "^0.4.23" }, "devDependencies": { diff --git a/utils.js b/utils.js index c2ac977..4be0290 100644 --- a/utils.js +++ b/utils.js @@ -7,8 +7,7 @@ import path from 'path'; import querystring from 'querystring'; import url from 'url'; import util from 'util'; - -import {parseString} from 'xml2js'; +import plist from 'plist'; function logWithInspect(object) { // https://stackoverflow.com/a/10729284/15487978 @@ -24,26 +23,28 @@ function isAppNameAllowed(appName) { return !disallowedAppNames.includes(appName); } -function getAppNamesToIconPaths(parsedDockData) { - const parsedAppData = parsedDockData.plist.dict[0] +function parseDockData(rawDockPlist) { + return plist.parse(rawDockPlist); +} - //logWithInspect(parsedAppData); +function getAppNamesWithIconPaths(parsedDockData) { + //logWithInspect(parsedDockData); - const persistentApps = parsedAppData.array[1].dict; - const _persistentOthers = parsedAppData.array[2].dict; - const _recentApps = parsedAppData.array[3].dict; + const persistentApps = parsedDockData['persistent-apps'] ?? []; + const persistentAppsWithoutSpacers = persistentApps.filter(item => item['tile-type'] === 'file-tile'); + const appNamesWithIconPaths = {}; - const result = {}; + for (const app of persistentAppsWithoutSpacers) { + const appName = app['tile-data']?.['file-label']; + const appDirectoryUrl = app['tile-data']?.['file-data']?.['_CFURLString']; - for (const parsedAppData of persistentApps ?? []) { - const appName = parsedAppData.dict[0].string[1]; - const appDirectoryUrl = parsedAppData.dict[0].dict?.[0].string[0]; if (appDirectoryUrl && isAppNameAllowed(appName)) { const appDirectory = url.fileURLToPath(appDirectoryUrl) - result[appName] = getIconPath(appDirectory); + appNamesWithIconPaths[appName] = getIconPath(appDirectory); } } - return result; + + return appNamesWithIconPaths; } /** @@ -139,14 +140,9 @@ export async function scanDockAndBringToWebApp(dockXmlPlist) { throw 'Dock data appears to be invalid. Expected: Apple plist XML.'; } - const parsedDockData = await new Promise((resolve, reject) => { - parseString(dockXmlPlist, function (error, result) { - return error ? reject(error) : resolve(result); - }); - }); - - const appNamesToIconPaths = getAppNamesToIconPaths(parsedDockData); - const appNames = Object.keys(appNamesToIconPaths); + const parsedDockData = parseDockData(dockXmlPlist); + const appNamesWithIconPaths = getAppNamesWithIconPaths(parsedDockData); + const appNames = Object.keys(appNamesWithIconPaths); if (appNames.length) { console.log('Found the following pinned apps in your dock:\n')