From d9fa8b2389baa5e431360c6fa0e1a2b05eca8bc1 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 10 Dec 2023 03:09:40 -0500 Subject: [PATCH 01/12] Log real AppImage path Signed-off-by: Alexandre Demers --- src/index.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.coffee b/src/index.coffee index 7c81eda..391a375 100644 --- a/src/index.coffee +++ b/src/index.coffee @@ -84,6 +84,7 @@ module.exports = class AutoLaunch # This will fail on the next launch, since AppImages are mount temporarily when executed in an everchanging mount folder. if process.env.APPIMAGE? path = process.env.APPIMAGE + console.log "Using real AppImage path at: %s", process.env.APPIMAGE # As stated in the .desktop spec, Exec key's value must be properly escaped with reserved characters. path = path.replace(/(\s+)/g, '\\$1') From 2aca4ab7935473704a9af39ba96a55ac3f789770 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 10 Dec 2023 03:48:04 -0500 Subject: [PATCH 02/12] Linux: use a lowercase name for the .desktop file Since we are using the appName for the .desktop file, this will be more coherent with other files under autostart and with the .desktop file names usually encountered in rpm and deb packages. Signed-off-by: Alexandre Demers --- src/AutoLaunchLinux.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AutoLaunchLinux.coffee b/src/AutoLaunchLinux.coffee index 8349339..6954355 100644 --- a/src/AutoLaunchLinux.coffee +++ b/src/AutoLaunchLinux.coffee @@ -25,18 +25,18 @@ module.exports = return fileBasedUtilities.createFile { data directory: @getDirectory() - filePath: @getFilePath appName + filePath: @getFilePath appName.toLowerCase() } # appName - {String} # Returns a Promise - disable: (appName) -> fileBasedUtilities.removeFile @getFilePath appName + disable: (appName) -> fileBasedUtilities.removeFile @getFilePath appName.toLowerCase() # appName - {String} # Returns a Promise which resolves to a {Boolean} - isEnabled: (appName) -> fileBasedUtilities.isEnabled @getFilePath appName + isEnabled: (appName) -> fileBasedUtilities.isEnabled @getFilePath appName.toLowerCase() ### Private ### @@ -46,4 +46,4 @@ module.exports = # appName - {String} # Returns a {String} - getFilePath: (appName) -> "#{@getDirectory()}#{appName}.desktop" \ No newline at end of file + getFilePath: (appName) -> "#{@getDirectory()}#{appName.toLowerCase()}.desktop" \ No newline at end of file From d002df65878277518489096b3be60431455c3a0f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 11 Dec 2023 01:40:05 -0500 Subject: [PATCH 03/12] README: bring back some details about how to find the path of the Appx There are a few ways to find the Appx' path needed to set auto-launch. The previous information was still relevent to complement this proposed steps. Signed-off-by: Alexandre Demers --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ee47a01..6e143f4 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,11 @@ If you're using [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows) #### Windows App Store apps -It requires some extra steps: +If you have your Electron-based app in the Windows Store and would like to include auto launch functionality, simply linking to the executable path will not work. The Appx packages required for Electron are sandboxed and the install location can only be accessed by the system itself. + +There is a way to bypass that - it will require you to know the developer ID, app ID and package name of your app. Then, instead of using the exec path, you will need to set the path in `AutoLaunch()` config to: `explorer.exe shell:AppsFolder\DEV_ID.APP_ID!PACKAGE_NAME`. One of the way you can find your apps details is by following [this article](http://winaero.com/blog/exclusive-how-to-start-a-modern-app-from-desktop-without-going-to-the-metro-start-screen/). Note that you might need to compile and submit your app to the store first to obtain these details. + +If you've already submitted your app, you may use the follow steps to find the path: - Install a beta version on your Windows device from Microsoft Store - Go to Windows apps folder: press `Win+R` and type `shell:AppsFolder` - Right-click and create shortcut on Desktop From 7fd0b232423662137ad7c5cad94a26fe7d4088ad Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 11 Dec 2023 01:03:28 -0500 Subject: [PATCH 04/12] Windows Appx: directly use explorer.exe in the startup registry entry Since in some cases Windows OS may not be on the C: nor in the Windows folder, and also because explorer.exe is an essential application in the Windows ecosystem, we can get ride of the C:\Windows and just call explorer.exe. Signed-off-by: Alexandre Demers --- src/AutoLaunchWindowsAppx.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AutoLaunchWindowsAppx.coffee b/src/AutoLaunchWindowsAppx.coffee index fe23b46..23699ca 100644 --- a/src/AutoLaunchWindowsAppx.coffee +++ b/src/AutoLaunchWindowsAppx.coffee @@ -24,7 +24,7 @@ module.exports = args += ' --hidden' if isHiddenOnLaunch - regKey.set appName, Winreg.REG_SZ, "\"C:\\Windows\\explorer.exe\" shell:AppsFolder\\#{pathToAutoLaunchedApp}#{args}", (err) -> + regKey.set appName, Winreg.REG_SZ, "\"explorer.exe\" shell:AppsFolder\\#{pathToAutoLaunchedApp}#{args}", (err) -> return reject(err) if err? resolve() From fb4a2667fc779033a52e4791f753969e9079c82c Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 11 Dec 2023 19:41:52 -0500 Subject: [PATCH 05/12] Unify Windows appX and regular app The only difference between appX and regular Windows app is the path. The first uses a combination of "DEV_ID.APP_ID!PACKAGE_NAME" relative to the AppsFolder. The second uses a regular path. Both app types register themselves in the registry in the same way. Manage both app types under a single code base. Signed-off-by: Alexandre Demers --- src/AutoLaunchWindows.coffee | 23 ++++++++------ src/AutoLaunchWindowsAppx.coffee | 52 -------------------------------- src/index.coffee | 4 +-- 3 files changed, 15 insertions(+), 64 deletions(-) delete mode 100644 src/AutoLaunchWindowsAppx.coffee diff --git a/src/AutoLaunchWindows.coffee b/src/AutoLaunchWindows.coffee index 0c5de6e..1702d1f 100644 --- a/src/AutoLaunchWindows.coffee +++ b/src/AutoLaunchWindows.coffee @@ -19,20 +19,25 @@ module.exports = # Returns a Promise enable: ({appName, appPath, isHiddenOnLaunch}) -> return new Promise (resolve, reject) -> - pathToAutoLaunchedApp = appPath - args = '' + # If they're using Electron and Squirrel.Windows, point to its Update.exe instead of the actual appPath + # Otherwise, we'll auto-launch an old version after the app has updated updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe') - # If they're using Electron and Squirrel.Windows, point to its Update.exe instead - # Otherwise, we'll auto-launch an old version after the app has updated if process.versions?.electron? and fs.existsSync updateDotExe - pathToAutoLaunchedApp = updateDotExe + pathToAutoLaunchedApp = "\"#{updateDotExe}\"" args = " --processStart \"#{path.basename(process.execPath)}\"" args += ' --process-start-args "--hidden"' if isHiddenOnLaunch else - args += ' --hidden' if isHiddenOnLaunch + # If this is an AppX (from Microsoft Store), the path doesn't point to a directory per se, + # but it's made of "DEV_ID.APP_ID!PACKAGE_NAME". It's used to identify the app in the AppsFolder. + # To launch the app, explorer.exe must be call in combination with its path relative to AppsFolder + if process.windowsStore? + pathToAutoLaunchedApp = "\"explorer.exe\" shell:AppsFolder\\#{appPath}" + else + pathToAutoLaunchedApp = "\"#{appPath}\"" + args = ' --hidden' if isHiddenOnLaunch - regKey.set appName, Winreg.REG_SZ, "\"#{pathToAutoLaunchedApp}\"#{args}", (err) -> + regKey.set appName, Winreg.REG_SZ, "#{pathToAutoLaunchedApp}#{args}", (err) -> return reject(err) if err? resolve() @@ -43,8 +48,8 @@ module.exports = return new Promise (resolve, reject) -> regKey.remove appName, (err) -> if err? - # The registry key should exist but in case it fails because it doesn't exist, resolve false instead - # rejecting with an error + # The registry key should exist but, in case it fails because it doesn't exist, + # resolve false instead of rejecting with an error if err.message.indexOf('The system was unable to find the specified registry key or value') isnt -1 return resolve false return reject err diff --git a/src/AutoLaunchWindowsAppx.coffee b/src/AutoLaunchWindowsAppx.coffee deleted file mode 100644 index 23699ca..0000000 --- a/src/AutoLaunchWindowsAppx.coffee +++ /dev/null @@ -1,52 +0,0 @@ -fs = require 'fs' -path = require 'path' -Winreg = require 'winreg' - - -regKey = new Winreg - hive: Winreg.HKCU - key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' - - -module.exports = - - ### Public ### - - # options - {Object} - # :appName - {String} - # :appPath - {String} - # :isHiddenOnLaunch - {Boolean} - # Returns a Promise - enable: ({appName, appPath, isHiddenOnLaunch}) -> - return new Promise (resolve, reject) -> - pathToAutoLaunchedApp = appPath - args = '' - - args += ' --hidden' if isHiddenOnLaunch - - regKey.set appName, Winreg.REG_SZ, "\"explorer.exe\" shell:AppsFolder\\#{pathToAutoLaunchedApp}#{args}", (err) -> - return reject(err) if err? - resolve() - - - # appName - {String} - # Returns a Promise - disable: (appName) -> - return new Promise (resolve, reject) -> - regKey.remove appName, (err) -> - if err? - # The registry key should exist but in case it fails because it doesn't exist, resolve false instead - # rejecting with an error - if err.message.indexOf('The system was unable to find the specified registry key or value') isnt -1 - return resolve false - return reject err - resolve() - - - # appName - {String} - # Returns a Promise which resolves to a {Boolean} - isEnabled: (appName) -> - return new Promise (resolve, reject) -> - regKey.get appName, (err, item) -> - return resolve false if err? - resolve(item?) diff --git a/src/index.coffee b/src/index.coffee index 3559453..0d17d57 100644 --- a/src/index.coffee +++ b/src/index.coffee @@ -36,9 +36,7 @@ module.exports = class AutoLaunch @fixOpts() @api = null - if process.windowsStore - @api = require './AutoLaunchWindowsAppx' - else if /^win/.test process.platform + if /^win/.test process.platform @api = require './AutoLaunchWindows' else if /darwin/.test process.platform @api = require './AutoLaunchMac' From fac9bfa8b3784294b9f80399616ebc499cf20431 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 11 Dec 2023 19:42:21 -0500 Subject: [PATCH 06/12] test: remove useless console call Signed-off-by: Alexandre Demers --- tests/index.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/index.coffee b/tests/index.coffee index 565b1f2..dac6a00 100644 --- a/tests/index.coffee +++ b/tests/index.coffee @@ -56,8 +56,7 @@ describe 'node-auto-launch', -> it 'should enable auto launch', (done) -> autoLaunch.enable() - .then (xxx) -> - console.log 'fefew', xxx + .then () -> autoLaunch.isEnabled() .then (enabled) -> expect(enabled).to.equal true From c9a556290d47f9b1a9dec13284f923ba6d0c5143 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 11 Dec 2023 21:11:53 -0500 Subject: [PATCH 07/12] Test Linux: check that the path name is properly escaped Signed-off-by: Alexandre Demers --- tests/index.coffee | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tests/index.coffee b/tests/index.coffee index dac6a00..0d660f1 100644 --- a/tests/index.coffee +++ b/tests/index.coffee @@ -95,10 +95,29 @@ describe 'node-auto-launch', -> if isLinux - it 'should use name option', (done) -> - expect(autoLaunch.opts.appName).to.equal 'node-auto-launch test' - done() - return + describe 'Honor provided appName', -> + it 'should use name option', (done) -> + expect(autoLaunch.opts.appName).to.equal 'node-auto-launch test' + done() + return + + # We should catch error + + describe 'Test path name', -> + beforeEach -> + delete autoLaunch + executablePath = './path with spaces/' + autoLaunch = new AutoLaunch + name: 'node-auto-launch test' + path: executablePath + autoLaunchHelper = new AutoLaunchHelper(autoLaunch) + + it 'should properly escape pathName', (done) -> + expect(autoLaunch.opts.appPath).not.to.equal executablePath + done() + return + + # We should catch error # Let's test some Mac-only options From 0acda7f1440bbf94c811585de628eb1703d6e493 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 11 Dec 2023 21:49:17 -0500 Subject: [PATCH 08/12] Test Linux: test, fixe and retest specific platform tests Signed-off-by: Alexandre Demers --- tests/index.coffee | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/index.coffee b/tests/index.coffee index 0d660f1..9fb9890 100644 --- a/tests/index.coffee +++ b/tests/index.coffee @@ -95,30 +95,24 @@ describe 'node-auto-launch', -> if isLinux - describe 'Honor provided appName', -> - it 'should use name option', (done) -> + describe '.appName', -> + it 'should honor name option', (done) -> expect(autoLaunch.opts.appName).to.equal 'node-auto-launch test' done() return - # We should catch error + describe 'testing path name', -> + executablePathLinux = path.resolve './path with spaces/' + autoLaunchLinux = new AutoLaunch + name: 'node-auto-launch test' + path: executablePathLinux + autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux) - describe 'Test path name', -> - beforeEach -> - delete autoLaunch - executablePath = './path with spaces/' - autoLaunch = new AutoLaunch - name: 'node-auto-launch test' - path: executablePath - autoLaunchHelper = new AutoLaunchHelper(autoLaunch) - - it 'should properly escape pathName', (done) -> - expect(autoLaunch.opts.appPath).not.to.equal executablePath + it 'should properly escape reserved caracters', (done) -> + expect(autoLaunchLinux.opts.appPath).not.to.equal executablePathLinux done() return - # We should catch error - # Let's test some Mac-only options return unless isMac From 2483d2b53388d10e98d4633daee09e4282755761 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 26 Dec 2023 19:43:41 -0500 Subject: [PATCH 09/12] Linux: honor appName Even if most Desktop files are written in lowercase (but not all) and there is no requirement on the matter, honor the appName case. Signed-off-by: Alexandre Demers --- src/AutoLaunchLinux.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AutoLaunchLinux.coffee b/src/AutoLaunchLinux.coffee index 6954355..8349339 100644 --- a/src/AutoLaunchLinux.coffee +++ b/src/AutoLaunchLinux.coffee @@ -25,18 +25,18 @@ module.exports = return fileBasedUtilities.createFile { data directory: @getDirectory() - filePath: @getFilePath appName.toLowerCase() + filePath: @getFilePath appName } # appName - {String} # Returns a Promise - disable: (appName) -> fileBasedUtilities.removeFile @getFilePath appName.toLowerCase() + disable: (appName) -> fileBasedUtilities.removeFile @getFilePath appName # appName - {String} # Returns a Promise which resolves to a {Boolean} - isEnabled: (appName) -> fileBasedUtilities.isEnabled @getFilePath appName.toLowerCase() + isEnabled: (appName) -> fileBasedUtilities.isEnabled @getFilePath appName ### Private ### @@ -46,4 +46,4 @@ module.exports = # appName - {String} # Returns a {String} - getFilePath: (appName) -> "#{@getDirectory()}#{appName.toLowerCase()}.desktop" \ No newline at end of file + getFilePath: (appName) -> "#{@getDirectory()}#{appName}.desktop" \ No newline at end of file From 981711f91ed6d6d0d78c1175d122275ea527fde2 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 26 Dec 2023 19:59:10 -0500 Subject: [PATCH 10/12] Be more explicit and coherent about createFile() parameters order We were putting the data first under Linux and Mac without being explicit about the parameter we were pointing. Signed-off-by: Alexandre Demers --- src/AutoLaunchLinux.coffee | 2 +- src/AutoLaunchMac.coffee | 2 +- src/fileBasedUtilities.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AutoLaunchLinux.coffee b/src/AutoLaunchLinux.coffee index 8349339..6973456 100644 --- a/src/AutoLaunchLinux.coffee +++ b/src/AutoLaunchLinux.coffee @@ -23,9 +23,9 @@ module.exports = Terminal=false""" return fileBasedUtilities.createFile { - data directory: @getDirectory() filePath: @getFilePath appName + data: data } diff --git a/src/AutoLaunchMac.coffee b/src/AutoLaunchMac.coffee index 1d29a17..1049a4b 100644 --- a/src/AutoLaunchMac.coffee +++ b/src/AutoLaunchMac.coffee @@ -40,9 +40,9 @@ module.exports = """ return fileBasedUtilities.createFile { - data directory: @getDirectory() filePath: @getFilePath appName + data: data } # Otherwise, use default method; use AppleScript to tell System Events to add a Login Item diff --git a/src/fileBasedUtilities.coffee b/src/fileBasedUtilities.coffee index 6845e76..8bb7850 100644 --- a/src/fileBasedUtilities.coffee +++ b/src/fileBasedUtilities.coffee @@ -8,9 +8,9 @@ module.exports = # This is essentially enabling auto-launching # options - {Object} - # :data - {String} # :directory - {String} # :filePath - {String} + # :data - {String} # Returns a Promise createFile: ({directory, filePath, data}) -> return new Promise (resolve, reject) -> From f3a992a01150511b76945ace1d13e8c82d701541 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 15:11:52 -0500 Subject: [PATCH 11/12] Bump version to 5.1.0 Signed-off-by: Alexandre Demers --- package-lock.json | 515 ++++++++++++++++++++++++++++++---------------- package.json | 4 +- 2 files changed, 345 insertions(+), 174 deletions(-) diff --git a/package-lock.json b/package-lock.json index 583612f..dbccae1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,36 @@ { "name": "auto-launch", - "version": "5.0.6", - "lockfileVersion": 1, + "version": "5.1.0", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@coffeelint/cli": { + "packages": { + "": { + "name": "auto-launch", + "version": "5.1.0", + "license": "MIT", + "dependencies": { + "applescript": "^1.0.0", + "mkdirp": "^0.5.1", + "untildify": "^3.0.2", + "winreg": "1.2.4" + }, + "devDependencies": { + "@coffeelint/cli": "^5.2.11", + "chai": "^3.5.0", + "coffeescript": "^2.7.0", + "mocha": "^3.0.0", + "teamwork-coffeelint-rules": "0.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@coffeelint/cli": { "version": "5.2.11", "resolved": "https://registry.npmjs.org/@coffeelint/cli/-/cli-5.2.11.tgz", "integrity": "sha512-CwWdjpKwije9+M2PKfbYPoLr5G4e8HN9Wtu/l8E8wlupuwqVdSZWzRkIu7qGMKZ1ERttFlxa+VGOavZ3wRIvHw==", "dev": true, - "requires": { + "dependencies": { "coffeescript": "2.7.0", "glob": "^8.0.1", "ignore": "^5.2.0", @@ -17,385 +38,475 @@ "strip-json-comments": "^3.1.1", "yargs": "^17.3.1" }, - "dependencies": { - "ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - } - } - }, - "ansi-regex": { + "bin": { + "coffeelint": "bin/coffeelint" + }, + "engines": { + "node": ">=12.x" + } + }, + "node_modules/@coffeelint/cli/node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@coffeelint/cli/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { + "dependencies": { "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "applescript": { + "node_modules/applescript": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz", "integrity": "sha1-u4evVoytA0pOSMS9r2Bno6JwExc=" }, - "assertion-error": { + "node_modules/assertion-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "brace-expansion": { + "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "browser-stdout": { + "node_modules/browser-stdout": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", "integrity": "sha512-7Rfk377tpSM9TWBEeHs0FlDZGoAIei2V/4MdZJoFMBFAK6BqLpxAIUepGRHGdPFgGsLb02PXovC4qddyHvQqTg==", "dev": true }, - "chai": { + "node_modules/chai": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, - "requires": { + "dependencies": { "assertion-error": "^1.0.1", "deep-eql": "^0.1.3", "type-detect": "^1.0.0" + }, + "engines": { + "node": ">= 0.4.0" } }, - "cliui": { + "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "requires": { + "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "coffeescript": { + "node_modules/coffeescript": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz", "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==", - "dev": true + "dev": true, + "bin": { + "cake": "bin/cake", + "coffee": "bin/coffee" + }, + "engines": { + "node": ">=6" + } }, - "color-convert": { + "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { + "dependencies": { "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "commander": { + "node_modules/commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==", "dev": true, - "requires": { + "dependencies": { "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" } }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "debug": { + "node_modules/debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "integrity": "sha512-E22fsyWPt/lr4/UgQLt/pXqerGMDsanhbnmqIS3VAXuDi1v3IpiwXe2oncEIondHSBuPDWRoK/pMjlvi8FuOXQ==", "dev": true, - "requires": { + "dependencies": { "ms": "2.0.0" } }, - "deep-eql": { + "node_modules/deep-eql": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", "dev": true, - "requires": { + "dependencies": { "type-detect": "0.1.1" }, - "dependencies": { - "type-detect": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", - "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", - "dev": true - } + "engines": { + "node": "*" + } + }, + "node_modules/deep-eql/node_modules/type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true, + "engines": { + "node": "*" } }, - "diff": { + "node_modules/diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", "integrity": "sha512-597ykPFhtJYaXqPq6fF7Vl1fXTKgPdLOntyxpmdzUOKiYGqK7zcnbplj5088+8qJnWdzXhyeau5iVr8HVo9dgg==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, - "emoji-regex": { + "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "escalade": { + "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "escape-string-regexp": { + "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, - "fs.realpath": { + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "function-bind": { + "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "get-caller-file": { + "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, - "glob": { + "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, - "requires": { + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "graceful-readlink": { + "node_modules/graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==", "dev": true }, - "growl": { + "node_modules/growl": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", "integrity": "sha512-RTBwDHhNuOx4F0hqzItc/siXCasGfC4DeWcBamclWd+6jWtBaeB/SGbMkGf0eiQoW7ib8JpvOgnUsmgMHI3Mfw==", "dev": true }, - "has-flag": { + "node_modules/has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "hasown": { + "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dev": true, - "requires": { + "dependencies": { "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "he": { + "node_modules/he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA==", - "dev": true + "dev": true, + "bin": { + "he": "bin/he" + } }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "requires": { + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "is-core-module": { + "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, - "requires": { + "dependencies": { "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-fullwidth-code-point": { + "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "json3": { + "node_modules/json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "integrity": "sha512-I5YLeauH3rIaE99EE++UeH2M2gSYo8/2TqDac7oZEH6D/DSQ4Woa628Qrfj1X9/OY5Mk5VvIDQaKCDchXaKrmA==", + "deprecated": "Please use the native JSON object instead of JSON 3", "dev": true }, - "lodash._baseassign": { + "node_modules/lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", "dev": true, - "requires": { + "dependencies": { "lodash._basecopy": "^3.0.0", "lodash.keys": "^3.0.0" } }, - "lodash._basecopy": { + "node_modules/lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", "dev": true }, - "lodash._basecreate": { + "node_modules/lodash._basecreate": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", "integrity": "sha512-EDem6C9iQpn7fxnGdmhXmqYGjCkStmDXT4AeyB2Ph8WKbglg4aJZczNkQglj+zWXcOEEkViK8THuV2JvugW47g==", "dev": true }, - "lodash._getnative": { + "node_modules/lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", "dev": true }, - "lodash._isiterateecall": { + "node_modules/lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", "dev": true }, - "lodash.create": { + "node_modules/lodash.create": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", "integrity": "sha512-IUfOYwDEbI8JbhW6psW+Ig01BOVK67dTSCUAbS58M0HBkPcAv/jHuxD+oJVP2tUCo3H9L6f/8GM6rxwY+oc7/w==", "dev": true, - "requires": { + "dependencies": { "lodash._baseassign": "^3.0.0", "lodash._basecreate": "^3.0.0", "lodash._isiterateecall": "^3.0.0" } }, - "lodash.isarguments": { + "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", "dev": true }, - "lodash.isarray": { + "node_modules/lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", "dev": true }, - "lodash.keys": { + "node_modules/lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", "dev": true, - "requires": { + "dependencies": { "lodash._getnative": "^3.0.0", "lodash.isarguments": "^3.0.0", "lodash.isarray": "^3.0.0" } }, - "minimatch": { + "node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, - "requires": { + "dependencies": { "brace-expansion": "^2.0.1" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - } - } - }, - "minimist": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, - "mkdirp": { + "node_modules/mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dependencies": { "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "mocha": { + "node_modules/mocha": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", "dev": true, - "requires": { + "dependencies": { "browser-stdout": "1.3.0", "commander": "2.9.0", "debug": "2.6.8", @@ -409,162 +520,216 @@ "mkdirp": "0.5.1", "supports-color": "3.1.2" }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 0.10.x", + "npm": ">= 1.4.x" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-mRyN/EsN2SyNhKWykF3eEGhDpeNplMWaW18Bmh76tnOqk5TbELAVwFAYOCmKVssOYFrYvvLMguiA+NXO3ZTuVA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-mRyN/EsN2SyNhKWykF3eEGhDpeNplMWaW18Bmh76tnOqk5TbELAVwFAYOCmKVssOYFrYvvLMguiA+NXO3ZTuVA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "ms": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "once": { + "node_modules/once": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "require-directory": { + "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "resolve": { + "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "requires": { + "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string-width": { + "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "requires": { + "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "requires": { + "dependencies": { "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "supports-color": { + "node_modules/supports-color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", "integrity": "sha512-F8dvPrZJtNzvDRX26eNXT4a7AecAvTGljmmnI39xEgSpbHKhQ7N0dO/NTxUExd0wuLHp4zbwYY7lvHq0aKpwrA==", "dev": true, - "requires": { + "dependencies": { "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" } }, - "supports-preserve-symlinks-flag": { + "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "teamwork-coffeelint-rules": { + "node_modules/teamwork-coffeelint-rules": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/teamwork-coffeelint-rules/-/teamwork-coffeelint-rules-0.0.1.tgz", "integrity": "sha1-XZ0hJSKaPg0nG7dGpu1cpc9gbnM=", "dev": true }, - "type-detect": { + "node_modules/type-detect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "untildify": { + "node_modules/untildify": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", - "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=" + "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=", + "engines": { + "node": ">=4" + } }, - "winreg": { + "node_modules/winreg": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz", "integrity": "sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=" }, - "wrap-ansi": { + "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "y18n": { + "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "yargs": { + "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "requires": { + "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", @@ -572,13 +737,19 @@ "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "yargs-parser": { + "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true + "dev": true, + "engines": { + "node": ">=12" + } } } } diff --git a/package.json b/package.json index 3ea96c2..8ed46d3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "auto-launch", - "version": "5.0.6", - "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", + "version": "5.1.0", + "description": "Launch node applications or executables at login (Mac, Windows, Linux and FreeBSD)", "main": "dist/index.js", "scripts": { "test": "mocha --compilers coffee:coffeescript/register tests/*.coffee", From 370d4f711d1272ff4169a3e9fb2acc7dfdcd250e Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 18 Jan 2024 00:45:43 -0500 Subject: [PATCH 12/12] Tests: merge common tests for all platforms and improve Linux' ones Merge macOS and common tests. Linux: improve and add testcases to honor .appName and cleanup behind us. Signed-off-by: Alexandre Demers --- tests/index.coffee | 258 +++++++++++++++++++++------------------------ 1 file changed, 121 insertions(+), 137 deletions(-) diff --git a/tests/index.coffee b/tests/index.coffee index 9fb9890..408236d 100644 --- a/tests/index.coffee +++ b/tests/index.coffee @@ -1,10 +1,13 @@ chai = require 'chai' +fs = require 'fs' path = require 'path' +untildify = require 'untildify' expect = chai.expect AutoLaunch = require '../src/' AutoLaunchHelper = require './helper' isMac = false +followsXDG = false if /^win/.test process.platform executablePath = path.resolve path.join './tests/executables', 'GitHubSetup.exe' @@ -12,7 +15,7 @@ else if /darwin/.test process.platform isMac = true executablePath = '/Applications/Calculator.app' else if (/linux/.test process.platform) or (/freebsd/.test process.platform) - isLinux = true + followsXDG = true executablePath = path.resolve path.join './tests/executables', 'hv3-linux-x86' console.log "Executable being used for tests:", executablePath @@ -22,165 +25,146 @@ describe 'node-auto-launch', -> autoLaunch = null autoLaunchHelper = null - beforeEach -> autoLaunch = new AutoLaunch name: 'node-auto-launch test' path: executablePath + mac: + useLaunchAgent: if isMac then true autoLaunchHelper = new AutoLaunchHelper(autoLaunch) - if not isMac - describe '.isEnabled', -> - beforeEach -> - autoLaunchHelper.ensureDisabled() - - it 'should be disabled', (done) -> - autoLaunch.isEnabled().then (enabled) -> - expect(enabled).to.equal false - done() - .catch done - return - - it 'should catch errors', (done) -> - autoLaunchHelper.mockApi - isEnabled: -> - Promise.reject() - - autoLaunch.isEnabled().catch done - return - - - describe '.enable', -> - beforeEach -> - autoLaunchHelper.ensureDisabled() - - it 'should enable auto launch', (done) -> - autoLaunch.enable() - .then () -> - autoLaunch.isEnabled() - .then (enabled) -> - expect(enabled).to.equal true - done() - .catch done - return - - it 'should catch errors', (done) -> - autoLaunchHelper.mockApi - enable: -> Promise.reject() + describe '.isEnabled', -> + beforeEach -> + autoLaunchHelper.ensureDisabled() - autoLaunch.enable().catch done - return + it 'should be disabled', (done) -> + autoLaunch.isEnabled().then (enabled) -> + expect(enabled).to.equal false + done() + .catch done + return + it 'should catch errors', (done) -> + autoLaunchHelper.mockApi + isEnabled: -> + Promise.reject() - describe '.disable', -> - beforeEach -> - autoLaunchHelper.ensureEnabled() + autoLaunch.isEnabled().catch done + return - it 'should disable auto launch', (done) -> - autoLaunch.disable() - .then -> autoLaunch.isEnabled() - .then (enabled) -> - expect(enabled).to.equal false - done() - .catch done - return + describe '.enable', -> + beforeEach -> + autoLaunchHelper.ensureDisabled() + + it 'should enable auto launch', (done) -> + autoLaunch.enable() + .then () -> + autoLaunch.isEnabled() + .then (enabled) -> + expect(enabled).to.equal true + done() + .catch done + return + + it 'should catch errors', (done) -> + autoLaunchHelper.mockApi + enable: -> Promise.reject() + + autoLaunch.enable().catch done + return + + describe '.disable', -> + beforeEach -> + autoLaunchHelper.ensureEnabled() - it 'should catch errors', (done) -> - autoLaunchHelper.mockApi - disable: -> - Promise.reject() + it 'should disable auto launch', (done) -> + autoLaunch.disable() + .then -> autoLaunch.isEnabled() + .then (enabled) -> + expect(enabled).to.equal false + done() + .catch done + return - autoLaunch.disable().catch done - return + it 'should catch errors', (done) -> + autoLaunchHelper.mockApi + disable: -> + Promise.reject() + autoLaunch.disable().catch done + return - if isLinux - describe '.appName', -> - it 'should honor name option', (done) -> - expect(autoLaunch.opts.appName).to.equal 'node-auto-launch test' - done() - return + return unless followsXDG - describe 'testing path name', -> - executablePathLinux = path.resolve './path with spaces/' - autoLaunchLinux = new AutoLaunch - name: 'node-auto-launch test' - path: executablePathLinux - autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux) + describe 'testing .appName', -> + beforeEach -> + autoLaunchLinux = null + autoLaunchHelper = null - it 'should properly escape reserved caracters', (done) -> - expect(autoLaunchLinux.opts.appPath).not.to.equal executablePathLinux + it 'without space', (done) -> + autoLaunchLinux = new AutoLaunch + name: 'node-auto-launch' + path: executablePath + autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux) + + autoLaunchLinux.enable() + .then () -> + desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunchLinux.opts.appName + '.desktop')) + fs.stat desktopEntryPath, (err, stats) => + if err + done err + expect(stats.isFile()).to.equal true done() - return + .catch done + return - - # Let's test some Mac-only options - return unless isMac - - describe 'mac.useLaunchAgent', -> - autoLaunchWithLaunchAgent = null - autoLaunchWithLaunchAgentHelper = null - - beforeEach -> - autoLaunchWithLaunchAgent = new AutoLaunch + it 'with space', (done) -> + autoLaunchLinux = new AutoLaunch name: 'node-auto-launch test' path: executablePath - mac: - useLaunchAgent: true - autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper autoLaunchWithLaunchAgent - - describe '.isEnabled', -> - beforeEach -> autoLaunchWithLaunchAgentHelper.ensureDisabled() - - it 'should be disabled', (done) -> - autoLaunchWithLaunchAgent.isEnabled().then (enabled) -> - expect(enabled).to.equal false + autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux) + + autoLaunchLinux.enable() + .then () -> + desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunchLinux.opts.appName + '.desktop')) + fs.stat desktopEntryPath, (err, stats) => + if err + done err + expect(stats.isFile()).to.equal true done() - .catch done - return - - it 'should catch errors', (done) -> - autoLaunchWithLaunchAgentHelper.mockApi - isEnabled: -> Promise.reject() - - autoLaunchWithLaunchAgent.isEnabled().catch done - return - - - describe '.enable', -> - beforeEach -> autoLaunchWithLaunchAgentHelper.ensureDisabled() - - it 'should enable auto launch', (done) -> - autoLaunchWithLaunchAgent.enable().then -> - autoLaunchWithLaunchAgent.isEnabled().then (enabled) -> - expect(enabled).to.equal true - done() - .catch done - return - - it 'should catch errors', (done) -> - autoLaunchWithLaunchAgentHelper.mockApi - enable: -> Promise.reject() - - autoLaunchWithLaunchAgent.enable().catch done - return + .catch done + return + it 'with capital letters', (done) -> + autoLaunchLinux = new AutoLaunch + name: 'Node-Auto-Launch' + path: executablePath + autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux) + + autoLaunchLinux.enable() + .then () -> + desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunchLinux.opts.appName + '.desktop')) + fs.stat desktopEntryPath, (err, stats) => + if err + done err + expect(stats.isFile()).to.equal true + done() + .catch done + return - describe '.disable', -> - beforeEach -> autoLaunchWithLaunchAgentHelper.ensureEnabled() + afterEach -> + autoLaunchHelper.ensureDisabled() - it 'should disable auto launch', (done) -> - autoLaunchWithLaunchAgent.disable() - .then -> autoLaunchWithLaunchAgent.isEnabled() - .then (enabled) -> - expect(enabled).to.equal false - done() - .catch done - return + describe 'testing path name', -> + executablePathLinux = path.resolve './path with spaces/' + autoLaunchLinux = new AutoLaunch + name: 'node-auto-launch test' + path: executablePathLinux + autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux) - it 'should catch errors', (done) -> - autoLaunchWithLaunchAgentHelper.mockApi - disable: -> Promise.reject() + it 'should properly escape reserved caracters', (done) -> + expect(autoLaunchLinux.opts.appPath).not.to.equal executablePathLinux + done() + return - autoLaunchWithLaunchAgent.disable().catch done - return + return