From c67f18070c2678e9226b05a74065707d3b98af52 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 17 Dec 2023 16:32:37 -0500 Subject: [PATCH 01/77] Decaffeinate Using decaffeinate npm module. Clean up has yet to come. Delete coffee files. Update .npmignore, .editorconfig and package.json Add .eslintrc.json Signed-off-by: Alexandre Demers --- .editorconfig | 4 - .eslintrc.json | 14 +++ .npmignore | 2 +- package.json | 27 +++-- src/AutoLaunchLinux.coffee | 49 -------- src/AutoLaunchLinux.js | 51 +++++++++ src/AutoLaunchMac.coffee | 99 ---------------- src/AutoLaunchMac.js | 111 ++++++++++++++++++ src/AutoLaunchWindows.coffee | 65 ----------- src/AutoLaunchWindows.js | 84 ++++++++++++++ src/fileBasedUtilities.coffee | 43 ------- src/fileBasedUtilities.js | 59 ++++++++++ src/index.coffee | 118 ------------------- src/index.js | 144 ++++++++++++++++++++++++ tests/helper.coffee | 14 --- tests/helper.js | 27 +++++ tests/index.coffee | 186 ------------------------------ tests/index.js | 205 ++++++++++++++++++++++++++++++++++ 18 files changed, 711 insertions(+), 591 deletions(-) create mode 100644 .eslintrc.json delete mode 100644 src/AutoLaunchLinux.coffee create mode 100644 src/AutoLaunchLinux.js delete mode 100644 src/AutoLaunchMac.coffee create mode 100644 src/AutoLaunchMac.js delete mode 100644 src/AutoLaunchWindows.coffee create mode 100644 src/AutoLaunchWindows.js delete mode 100644 src/fileBasedUtilities.coffee create mode 100644 src/fileBasedUtilities.js delete mode 100644 src/index.coffee create mode 100644 src/index.js delete mode 100644 tests/helper.coffee create mode 100644 tests/helper.js delete mode 100644 tests/index.coffee create mode 100644 tests/index.js diff --git a/.editorconfig b/.editorconfig index a9e47cf..b9bbff5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,10 +8,6 @@ charset = "utf8" trim_trailing_whitespace = true insert_final_newline = true -[*.coffee] -indent_style = space -indent_size = 4 - [*.js] indent_style = space indent_size = 4 diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..316e980 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "extends": "airbnb-base", + "env": { + "browser": true, + "mocha": true + }, + "parser": "babel-eslint", + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "class-methods-use-this": 0 + } +} \ No newline at end of file diff --git a/.npmignore b/.npmignore index cd8b52d..fc4b35d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,5 @@ * -!dist/* +!src/* !README.md !LICENSE.md !package.json \ No newline at end of file diff --git a/package.json b/package.json index 3ea96c2..9478e50 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,14 @@ "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "main": "dist/index.js", "scripts": { - "test": "mocha --compilers coffee:coffeescript/register tests/*.coffee", - "lint": "coffeelint -f ./node_modules/teamwork-coffeelint-rules/coffeelint.json src/ tests/", - "build": "coffee -c -o dist/ src/" + "lint": "eslint --ext .ts src script test", + "lint:fix": "pnpm lint --fix", + "test": "mocha tests/**/*.js --reporter spec" + }, + "pre-commit": { + "run": [ + "test" + ] }, "engines": { "node": ">=12.0.0" @@ -32,20 +37,18 @@ "url": "https://github.com/4ver/node-auto-launch/issues" }, "devDependencies": { - "@coffeelint/cli": "^5.2.11", + "@babel/eslint-parser": "^7.23.0", "chai": "^3.5.0", - "coffeescript": "^2.7.0", - "mocha": "^3.0.0", - "teamwork-coffeelint-rules": "0.0.1" + "eslint": "^8.55.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.29.0", + "mocha": "^4.0.0" }, "homepage": "https://github.com/4ver/node-auto-launch", "dependencies": { "applescript": "^1.0.0", - "mkdirp": "^0.5.1", - "untildify": "^3.0.2", + "mkdirp": "^3.0.0", + "untildify": "^5.0.0", "winreg": "1.2.4" - }, - "overrides": { - "graceful-fs": "^4.2.11" } } diff --git a/src/AutoLaunchLinux.coffee b/src/AutoLaunchLinux.coffee deleted file mode 100644 index 6954355..0000000 --- a/src/AutoLaunchLinux.coffee +++ /dev/null @@ -1,49 +0,0 @@ -untildify = require 'untildify' -fileBasedUtilities = require './fileBasedUtilities' - -module.exports = - - ### Public ### - - # options - {Object} - # :appName - {String} - # :appPath - {String} - # :isHiddenOnLaunch - {Boolean} - # Returns a Promise - enable: ({appName, appPath, isHiddenOnLaunch}) -> - hiddenArg = if isHiddenOnLaunch then '--hidden' else '' - - data = """[Desktop Entry] - Type=Application - Version=1.0 - Name=#{appName} - Comment=#{appName} startup script - Exec=#{appPath} #{hiddenArg} - StartupNotify=false - Terminal=false""" - - return fileBasedUtilities.createFile { - data - directory: @getDirectory() - filePath: @getFilePath appName.toLowerCase() - } - - - # appName - {String} - # Returns a Promise - disable: (appName) -> fileBasedUtilities.removeFile @getFilePath appName.toLowerCase() - - - # appName - {String} - # Returns a Promise which resolves to a {Boolean} - isEnabled: (appName) -> fileBasedUtilities.isEnabled @getFilePath appName.toLowerCase() - - - ### Private ### - - # Returns a {String} - getDirectory: -> untildify '~/.config/autostart/' - - # appName - {String} - # Returns a {String} - getFilePath: (appName) -> "#{@getDirectory()}#{appName.toLowerCase()}.desktop" \ No newline at end of file diff --git a/src/AutoLaunchLinux.js b/src/AutoLaunchLinux.js new file mode 100644 index 0000000..42b1525 --- /dev/null +++ b/src/AutoLaunchLinux.js @@ -0,0 +1,51 @@ +const untildify = require('untildify'); +const fileBasedUtilities = require('./fileBasedUtilities'); + +module.exports = { + + /* Public */ + + // options - {Object} + // :appName - {String} + // :appPath - {String} + // :isHiddenOnLaunch - {Boolean} + // Returns a Promise + enable({appName, appPath, isHiddenOnLaunch}) { + const hiddenArg = isHiddenOnLaunch ? '--hidden' : ''; + + const data = `[Desktop Entry] +Type=Application +Version=1.0 +Name=${appName} +Comment=${appName} startup script +Exec=${appPath} ${hiddenArg} +StartupNotify=false +Terminal=false`; + + return fileBasedUtilities.createFile({ + data, + directory: this.getDirectory(), + filePath: this.getFilePath(appName.toLowerCase()) + }); + }, + + + // appName - {String} + // Returns a Promise + disable(appName) { return fileBasedUtilities.removeFile(this.getFilePath(appName.toLowerCase())); }, + + + // appName - {String} + // Returns a Promise which resolves to a {Boolean} + isEnabled(appName) { return fileBasedUtilities.isEnabled(this.getFilePath(appName.toLowerCase())); }, + + + /* Private */ + + // Returns a {String} + getDirectory() { return untildify('~/.config/autostart/'); }, + + // appName - {String} + // Returns a {String} + getFilePath(appName) { return `${this.getDirectory()}${appName.toLowerCase()}.desktop`; } +}; \ No newline at end of file diff --git a/src/AutoLaunchMac.coffee b/src/AutoLaunchMac.coffee deleted file mode 100644 index 1d29a17..0000000 --- a/src/AutoLaunchMac.coffee +++ /dev/null @@ -1,99 +0,0 @@ -applescript = require 'applescript' -untildify = require 'untildify' -fileBasedUtilities = require './fileBasedUtilities' - - -module.exports = - - ### Public ### - - # options - {Object} - # :appName - {String} - # :appPath - {String} - # :isHiddenOnLaunch - {Boolean} - # :mac - (Optional) {Object} - # :useLaunchAgent - (Optional) {Boolean} - # Returns a Promise - enable: ({appName, appPath, isHiddenOnLaunch, mac}) -> - - # Add the file if we're using a Launch Agent - if mac.useLaunchAgent - programArguments = [appPath] - programArguments.push '--hidden' if isHiddenOnLaunch - programArgumentsSection = programArguments - .map((argument) -> " #{argument}") - .join('\n') - - data = """ - - - - Label - #{appName} - ProgramArguments - - #{programArgumentsSection} - - RunAtLoad - - - """ - - return fileBasedUtilities.createFile { - data - directory: @getDirectory() - filePath: @getFilePath appName - } - - # Otherwise, use default method; use AppleScript to tell System Events to add a Login Item - - isHiddenValue = if isHiddenOnLaunch then 'true' else 'false' - properties = "{path:\"#{appPath}\", hidden:#{isHiddenValue}, name:\"#{appName}\"}" - - return @execApplescriptCommand "make login item at end with properties #{properties}" - - - # appName - {String} - # mac - {Object} - # :useLaunchAgent - {Object} - # Returns a Promise - disable: (appName, mac) -> - # Delete the file if we're using a Launch Agent - return fileBasedUtilities.removeFile @getFilePath appName if mac.useLaunchAgent - - # Otherwise remove the Login Item - return @execApplescriptCommand "delete login item \"#{appName}\"" - - - # appName - {String} - # mac - {Object} - # :useLaunchAgent - {Object} - # Returns a Promise which resolves to a {Boolean} - isEnabled: (appName, mac) -> - # Check if the Launch Agent file exists - return fileBasedUtilities.isEnabled @getFilePath appName if mac.useLaunchAgent - - # Otherwise check if a Login Item exists for our app - return @execApplescriptCommand('get the name of every login item').then (loginItems) -> - return loginItems? and appName in loginItems - - - ### Private ### - - - # commandSuffix - {String} - # Returns a Promise - execApplescriptCommand: (commandSuffix) -> - return new Promise (resolve, reject) -> - applescript.execString "tell application \"System Events\" to #{commandSuffix}", (err, result) -> - return reject err if err? - resolve result - - - # Returns a {String} - getDirectory: -> untildify '~/Library/LaunchAgents/' - - - # appName - {String} - # Returns a {String} - getFilePath: (appName) -> "#{@getDirectory()}#{appName}.plist" \ No newline at end of file diff --git a/src/AutoLaunchMac.js b/src/AutoLaunchMac.js new file mode 100644 index 0000000..2cb6784 --- /dev/null +++ b/src/AutoLaunchMac.js @@ -0,0 +1,111 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md + */ +const applescript = require('applescript'); +const untildify = require('untildify'); +const fileBasedUtilities = require('./fileBasedUtilities'); + + +module.exports = { + + /* Public */ + + // options - {Object} + // :appName - {String} + // :appPath - {String} + // :isHiddenOnLaunch - {Boolean} + // :mac - (Optional) {Object} + // :useLaunchAgent - (Optional) {Boolean} + // Returns a Promise + enable({appName, appPath, isHiddenOnLaunch, mac}) { + + // Add the file if we're using a Launch Agent + if (mac.useLaunchAgent) { + const programArguments = [appPath]; + if (isHiddenOnLaunch) { programArguments.push('--hidden'); } + const programArgumentsSection = programArguments + .map(argument => ` ${argument}`) + .join('\n'); + + const data = ` + + + + Label + ${appName} + ProgramArguments + + ${programArgumentsSection} + + RunAtLoad + + +`; + + return fileBasedUtilities.createFile({ + data, + directory: this.getDirectory(), + filePath: this.getFilePath(appName) + }); + } + + // Otherwise, use default method; use AppleScript to tell System Events to add a Login Item + + const isHiddenValue = isHiddenOnLaunch ? 'true' : 'false'; + const properties = `{path:\"${appPath}\", hidden:${isHiddenValue}, name:\"${appName}\"}`; + + return this.execApplescriptCommand(`make login item at end with properties ${properties}`); + }, + + + // appName - {String} + // mac - {Object} + // :useLaunchAgent - {Object} + // Returns a Promise + disable(appName, mac) { + // Delete the file if we're using a Launch Agent + if (mac.useLaunchAgent) { return fileBasedUtilities.removeFile(this.getFilePath(appName)); } + + // Otherwise remove the Login Item + return this.execApplescriptCommand(`delete login item \"${appName}\"`); + }, + + + // appName - {String} + // mac - {Object} + // :useLaunchAgent - {Object} + // Returns a Promise which resolves to a {Boolean} + isEnabled(appName, mac) { + // Check if the Launch Agent file exists + if (mac.useLaunchAgent) { return fileBasedUtilities.isEnabled(this.getFilePath(appName)); } + + // Otherwise check if a Login Item exists for our app + return this.execApplescriptCommand('get the name of every login item').then(loginItems => (loginItems != null) && Array.from(loginItems).includes(appName)); + }, + + + /* Private */ + + + // commandSuffix - {String} + // Returns a Promise + execApplescriptCommand(commandSuffix) { + return new Promise((resolve, reject) => applescript.execString(`tell application \"System Events\" to ${commandSuffix}`, function(err, result) { + if (err != null) { return reject(err); } + return resolve(result); + })); + }, + + + // Returns a {String} + getDirectory() { return untildify('~/Library/LaunchAgents/'); }, + + + // appName - {String} + // Returns a {String} + getFilePath(appName) { return `${this.getDirectory()}${appName}.plist`; } +}; \ No newline at end of file diff --git a/src/AutoLaunchWindows.coffee b/src/AutoLaunchWindows.coffee deleted file mode 100644 index 1702d1f..0000000 --- a/src/AutoLaunchWindows.coffee +++ /dev/null @@ -1,65 +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) -> - # 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 process.versions?.electron? and fs.existsSync updateDotExe - pathToAutoLaunchedApp = "\"#{updateDotExe}\"" - args = " --processStart \"#{path.basename(process.execPath)}\"" - args += ' --process-start-args "--hidden"' if isHiddenOnLaunch - else - # 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) -> - 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 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 - 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/AutoLaunchWindows.js b/src/AutoLaunchWindows.js new file mode 100644 index 0000000..c1b680b --- /dev/null +++ b/src/AutoLaunchWindows.js @@ -0,0 +1,84 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md + */ +const fs = require('fs'); +const path = require('path'); +const winreg = require('winreg'); + + +const 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(function(resolve, reject) { + // 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 + let args = ''; + let pathToAutoLaunchedApp; + const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe'); + + if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) { + pathToAutoLaunchedApp = `\"${updateDotExe}\"`; + args = ` --processStart \"${path.basename(process.execPath)}\"`; + if (isHiddenOnLaunch) { args += ' --process-start-args "--hidden"'; } + } else { + // 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 != null) { + pathToAutoLaunchedApp = `\"explorer.exe\" shell:AppsFolder\\${appPath}`; + } else { + pathToAutoLaunchedApp = `\"${appPath}\"`; + } + if (isHiddenOnLaunch) { args = ' --hidden'; } + } + + return regKey.set(appName, winreg.REG_SZ, `${pathToAutoLaunchedApp}${args}`, function(err) { + if (err != null) { return reject(err); } + return resolve(); + }); + }); + }, + + + // appName - {String} + // Returns a Promise + disable(appName) { + return new Promise((resolve, reject) => regKey.remove(appName, function(err) { + if (err != null) { + // 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') !== -1) { + return resolve(false); + } + return reject(err); + } + return resolve(); + })); + }, + + + // appName - {String} + // Returns a Promise which resolves to a {Boolean} + isEnabled(appName) { + return new Promise((resolve, reject) => regKey.get(appName, function(err, item) { + if (err != null) { return resolve(false); } + return resolve(item != null); + })); + } +}; diff --git a/src/fileBasedUtilities.coffee b/src/fileBasedUtilities.coffee deleted file mode 100644 index 6845e76..0000000 --- a/src/fileBasedUtilities.coffee +++ /dev/null @@ -1,43 +0,0 @@ -fs = require 'fs' -mkdirp = require 'mkdirp' - -# Public: a few utils for file-based auto-launching -module.exports = - - ### Public ### - - # This is essentially enabling auto-launching - # options - {Object} - # :data - {String} - # :directory - {String} - # :filePath - {String} - # Returns a Promise - createFile: ({directory, filePath, data}) -> - return new Promise (resolve, reject) -> - mkdirp directory, (mkdirErr) -> - return reject mkdirErr if mkdirErr? - fs.writeFile filePath, data, (writeErr) -> - return reject(writeErr) if writeErr? - resolve() - - - # filePath - {String} - isEnabled: (filePath) -> - return new Promise (resolve, reject) => - fs.stat filePath, (err, stat) -> - return resolve false if err? - resolve(stat?) - - - # This is essentially disabling auto-launching - # filePath - {String} - # Returns a Promise - removeFile: (filePath) -> - return new Promise (resolve, reject) => - fs.stat filePath, (statErr) -> - # If it doesn't exist, this is good so resolve - return resolve() if statErr? - - fs.unlink filePath, (unlinkErr) -> - return reject(unlinkErr) if unlinkErr? - resolve() \ No newline at end of file diff --git a/src/fileBasedUtilities.js b/src/fileBasedUtilities.js new file mode 100644 index 0000000..6ba7056 --- /dev/null +++ b/src/fileBasedUtilities.js @@ -0,0 +1,59 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md + */ +const fs = require('fs'); +const mkdirp = require('mkdirp'); + +// Public: a few utils for file-based auto-launching +module.exports = { + + /* Public */ + + // This is essentially enabling auto-launching + // options - {Object} + // :data - {String} + // :directory - {String} + // :filePath - {String} + // Returns a Promise + createFile({directory, filePath, data}) { + return new Promise((resolve, reject) => mkdirp(directory, function(mkdirErr) { + if (mkdirErr != null) { return reject(mkdirErr); } + return fs.writeFile(filePath, data, function(writeErr) { + if (writeErr != null) { return reject(writeErr); } + return resolve(); + }); + })); + }, + + + // filePath - {String} + isEnabled(filePath) { + return new Promise((resolve, reject) => { + return fs.stat(filePath, function(err, stat) { + if (err != null) { return resolve(false); } + return resolve(stat != null); + }); + }); + }, + + + // This is essentially disabling auto-launching + // filePath - {String} + // Returns a Promise + removeFile(filePath) { + return new Promise((resolve, reject) => { + return fs.stat(filePath, function(statErr) { + // If it doesn't exist, this is good so resolve + if (statErr != null) { return resolve(); } + + return fs.unlink(filePath, function(unlinkErr) { + if (unlinkErr != null) { return reject(unlinkErr); } + return resolve(); + }); + }); + }); + } +}; \ No newline at end of file diff --git a/src/index.coffee b/src/index.coffee deleted file mode 100644 index 0d17d57..0000000 --- a/src/index.coffee +++ /dev/null @@ -1,118 +0,0 @@ -pathTools = require 'path' - -# Public: The main auto-launch class -module.exports = class AutoLaunch - - ### Public ### - - # options - {Object} - # :name - {String} - # :isHidden - (Optional) {Boolean} - # :mac - (Optional) {Object} - # :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript - # to add Login Item - # :path - (Optional) {String} - constructor: ({name, isHidden, mac, path}) -> - throw new Error 'You must specify a name' unless name? - - @opts = - appName: name - isHiddenOnLaunch: if isHidden? then isHidden else false - mac: mac ? {} - - versions = process?.versions - if path? - # Verify that the path is absolute - throw new Error 'path must be absolute' unless (pathTools.isAbsolute path) or process.windowsStore - @opts.appPath = path - - else if versions? and (versions.nw? or versions['node-webkit']? or versions.electron?) - # This appPath will need to be fixed later depending of the OS used - @opts.appPath = process.execPath - - else - throw new Error 'You must give a path (this is only auto-detected for NW.js and Electron apps)' - - @fixOpts() - - @api = null - if /^win/.test process.platform - @api = require './AutoLaunchWindows' - else if /darwin/.test process.platform - @api = require './AutoLaunchMac' - else if (/linux/.test process.platform) or (/freebsd/.test process.platform) - @api = require './AutoLaunchLinux' - else - throw new Error 'Unsupported platform' - - - enable: => @api.enable @opts - - - disable: => @api.disable @opts.appName, @opts.mac - - - # Returns a Promise which resolves to a {Boolean} - isEnabled: => @api.isEnabled @opts.appName, @opts.mac - - - ### Private ### - - - # Corrects the path to point to the outer .app - # path - {String} - # macOptions - {Object} - # Returns a {String} - fixMacExecPath: (path, macOptions) -> - # This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" - # (the default Electron app structure for example) - # It will also match apps whose outer app's basename is different to the rest but the inner app and executable's - # basenames are matching (a typical distributed NW.js app for example) - # Does not match when the three are different - # Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron - # executable in the outer app - path = path.replace /(^.+?[^\/]+?\.app)\/Contents\/(Frameworks\/((\1|[^\/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1' - # When using a launch agent, it needs the inner executable path - path = path.replace /\.app\/Contents\/MacOS\/[^\/]*$/, '.app' unless macOptions.useLaunchAgent - return path - - # Under Linux and FreeBSD, fix the ExecPath when packaged as AppImage and escape the spaces correctly - # path - {String} - # Returns a {String} - fixLinuxExecPath: (path) -> - # If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used. - # 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') - - return path - - - fixOpts: => - @opts.appPath = @opts.appPath.replace /\/$/, '' - - if /darwin/.test process.platform - @opts.appPath = @fixMacExecPath(@opts.appPath, @opts.mac) - - if (/linux/.test process.platform) or (/freebsd/.test process.platform) - @opts.appPath = @fixLinuxExecPath(@opts.appPath) - - # Comment: why are we fiddling with the appName while this is a mandatory when calling the constructor. - # Shouldn't we honor the provided name? Windows use the name as a descriptor, macOS uses - # it for naming the .plist file and Linux/FreeBSD use it to name the .desktop file. - if @opts.appPath.indexOf('\\') isnt -1 - - tempPath = @opts.appPath.split '\\' - @opts.appName = tempPath[tempPath.length - 1] - @opts.appName = @opts.appName.substr(0, @opts.appName.length - '.exe'.length) - - if /darwin/.test process.platform - tempPath = @opts.appPath.split '/' - @opts.appName = tempPath[tempPath.length - 1] - # Remove ".app" from the appName if it exists - if @opts.appName.indexOf('.app', @opts.appName.length - '.app'.length) isnt -1 - @opts.appName = @opts.appName.substr(0, @opts.appName.length - '.app'.length) \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..c879340 --- /dev/null +++ b/src/index.js @@ -0,0 +1,144 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md + */ +let AutoLaunch; +const pathTools = require('path'); + +// Public: The main auto-launch class +module.exports = (AutoLaunch = class AutoLaunch { + + /* Public */ + + // options - {Object} + // :name - {String} + // :isHidden - (Optional) {Boolean} + // :mac - (Optional) {Object} + // :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript + // to add Login Item + // :path - (Optional) {String} + constructor({name, isHidden, mac, path}) { + this.enable = this.enable.bind(this); + this.disable = this.disable.bind(this); + this.isEnabled = this.isEnabled.bind(this); + this.fixOpts = this.fixOpts.bind(this); + if (name == null) { throw new Error('You must specify a name'); } + + this.opts = { + appName: name, + isHiddenOnLaunch: (isHidden != null) ? isHidden : false, + mac: mac != null ? mac : {} + }; + + const versions = typeof process !== 'undefined' && process !== null ? process.versions : undefined; + if (path != null) { + // Verify that the path is absolute + if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { throw new Error('path must be absolute'); } + this.opts.appPath = path; + + } else if ((versions != null) && ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) { + // This appPath will need to be fixed later depending of the OS used + this.opts.appPath = process.execPath; + + } else { + throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); + } + + this.fixOpts(); + + this.api = null; + if (/^win/.test(process.platform)) { + this.api = require('./AutoLaunchWindows'); + } else if (/darwin/.test(process.platform)) { + this.api = require('./AutoLaunchMac'); + } else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { + this.api = require('./AutoLaunchLinux'); + } else { + throw new Error('Unsupported platform'); + } + } + + + enable() { return this.api.enable(this.opts); } + + + disable() { return this.api.disable(this.opts.appName, this.opts.mac); } + + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { return this.api.isEnabled(this.opts.appName, this.opts.mac); } + + + /* Private */ + + + // Corrects the path to point to the outer .app + // path - {String} + // macOptions - {Object} + // Returns a {String} + fixMacExecPath(path, macOptions) { + // This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" + // (the default Electron app structure for example) + // It will also match apps whose outer app's basename is different to the rest but the inner app and executable's + // basenames are matching (a typical distributed NW.js app for example) + // Does not match when the three are different + // Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron + // executable in the outer app + path = path.replace(/(^.+?[^\/]+?\.app)\/Contents\/(Frameworks\/((\1|[^\/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1'); + // When using a launch agent, it needs the inner executable path + if (!macOptions.useLaunchAgent) { path = path.replace(/\.app\/Contents\/MacOS\/[^\/]*$/, '.app'); } + return path; + } + + // Under Linux and FreeBSD, fix the ExecPath when packaged as AppImage and escape the spaces correctly + // path - {String} + // Returns a {String} + fixLinuxExecPath(path) { + // If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used. + // This will fail on the next launch, since AppImages are mount temporarily when executed in an everchanging mount folder. + if (process.env.APPIMAGE != null) { + 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'); + + return path; + } + + + fixOpts() { + let tempPath; + this.opts.appPath = this.opts.appPath.replace(/\/$/, ''); + + if (/darwin/.test(process.platform)) { + this.opts.appPath = this.fixMacExecPath(this.opts.appPath, this.opts.mac); + } + + if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { + this.opts.appPath = this.fixLinuxExecPath(this.opts.appPath); + } + + // Comment: why are we fiddling with the appName while this is a mandatory when calling the constructor. + // Shouldn't we honor the provided name? Windows use the name as a descriptor, macOS uses + // it for naming the .plist file and Linux/FreeBSD use it to name the .desktop file. + if (this.opts.appPath.indexOf('\\') !== -1) { + + tempPath = this.opts.appPath.split('\\'); + this.opts.appName = tempPath[tempPath.length - 1]; + this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.exe'.length); + } + + if (/darwin/.test(process.platform)) { + tempPath = this.opts.appPath.split('/'); + this.opts.appName = tempPath[tempPath.length - 1]; + // Remove ".app" from the appName if it exists + if (this.opts.appName.indexOf('.app', this.opts.appName.length - '.app'.length) !== -1) { + return this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.app'.length); + } + } + } +}); \ No newline at end of file diff --git a/tests/helper.coffee b/tests/helper.coffee deleted file mode 100644 index 1fa6d02..0000000 --- a/tests/helper.coffee +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = class AutoLaunchHelper - constructor: (autoLaunch) -> - @autoLaunch = autoLaunch - - ensureEnabled: -> - @autoLaunch.isEnabled().then (enabled) => - @autoLaunch.enable() unless enabled - - ensureDisabled: -> - @autoLaunch.isEnabled().then (enabled) => - @autoLaunch.disable() if enabled - - mockApi: (stubs) -> - @autoLaunch.api = stubs diff --git a/tests/helper.js b/tests/helper.js new file mode 100644 index 0000000..bee342e --- /dev/null +++ b/tests/helper.js @@ -0,0 +1,27 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md + */ +let AutoLaunchHelper; +module.exports = (AutoLaunchHelper = class AutoLaunchHelper { + constructor(autoLaunch) { + this.autoLaunch = autoLaunch; + } + + ensureEnabled() { + return this.autoLaunch.isEnabled().then(enabled => { + if (!enabled) { return this.autoLaunch.enable(); } + }); + } + + ensureDisabled() { + return this.autoLaunch.isEnabled().then(enabled => { + if (enabled) { return this.autoLaunch.disable(); } + }); + } + + mockApi(stubs) { + return this.autoLaunch.api = stubs; + } +}); diff --git a/tests/index.coffee b/tests/index.coffee deleted file mode 100644 index 9fb9890..0000000 --- a/tests/index.coffee +++ /dev/null @@ -1,186 +0,0 @@ -chai = require 'chai' -path = require 'path' -expect = chai.expect -AutoLaunch = require '../src/' -AutoLaunchHelper = require './helper' - -isMac = false - -if /^win/.test process.platform - executablePath = path.resolve path.join './tests/executables', 'GitHubSetup.exe' -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 - executablePath = path.resolve path.join './tests/executables', 'hv3-linux-x86' - -console.log "Executable being used for tests:", executablePath - -# General tests for all platforms -describe 'node-auto-launch', -> - autoLaunch = null - autoLaunchHelper = null - - - beforeEach -> - autoLaunch = new AutoLaunch - name: 'node-auto-launch test' - path: executablePath - 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() - - autoLaunch.enable().catch done - return - - - describe '.disable', -> - beforeEach -> - autoLaunchHelper.ensureEnabled() - - it 'should disable auto launch', (done) -> - autoLaunch.disable() - .then -> autoLaunch.isEnabled() - .then (enabled) -> - expect(enabled).to.equal false - done() - .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 - - 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 properly escape reserved caracters', (done) -> - expect(autoLaunchLinux.opts.appPath).not.to.equal executablePathLinux - done() - return - - - # Let's test some Mac-only options - return unless isMac - - describe 'mac.useLaunchAgent', -> - autoLaunchWithLaunchAgent = null - autoLaunchWithLaunchAgentHelper = null - - beforeEach -> - autoLaunchWithLaunchAgent = 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 - 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 - - - describe '.disable', -> - beforeEach -> autoLaunchWithLaunchAgentHelper.ensureEnabled() - - it 'should disable auto launch', (done) -> - autoLaunchWithLaunchAgent.disable() - .then -> autoLaunchWithLaunchAgent.isEnabled() - .then (enabled) -> - expect(enabled).to.equal false - done() - .catch done - return - - it 'should catch errors', (done) -> - autoLaunchWithLaunchAgentHelper.mockApi - disable: -> Promise.reject() - - autoLaunchWithLaunchAgent.disable().catch done - return diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000..3697313 --- /dev/null +++ b/tests/index.js @@ -0,0 +1,205 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md + */ +let executablePath, isLinux; +const chai = require('chai'); +const path = require('path'); +const { + expect +} = chai; +const AutoLaunch = require('../src/'); +const AutoLaunchHelper = require('./helper'); + +let isMac = false; + +if (/^win/.test(process.platform)) { + executablePath = path.resolve(path.join('./tests/executables', 'GitHubSetup.exe')); +} else if (/darwin/.test(process.platform)) { + isMac = true; + executablePath = '/Applications/Calculator.app'; +} else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { + isLinux = true; + executablePath = path.resolve(path.join('./tests/executables', 'hv3-linux-x86')); +} + +console.log("Executable being used for tests:", executablePath); + +// General tests for all platforms +describe('node-auto-launch', function() { + let autoLaunch = null; + let autoLaunchHelper = null; + + + beforeEach(function() { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath + }); + return autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + }); + + if (!isMac) { + describe('.isEnabled', function() { + beforeEach(() => autoLaunchHelper.ensureDisabled()); + + it('should be disabled', function(done) { + autoLaunch.isEnabled().then(function(enabled) { + expect(enabled).to.equal(false); + return done();}).catch(done); + }); + + return it('should catch errors', function(done) { + autoLaunchHelper.mockApi({ + isEnabled() { + return Promise.reject(); + } + }); + + autoLaunch.isEnabled().catch(done); + }); + }); + + + describe('.enable', function() { + beforeEach(() => autoLaunchHelper.ensureDisabled()); + + it('should enable auto launch', function(done) { + autoLaunch.enable() + .then(() => autoLaunch.isEnabled()).then(function(enabled) { + expect(enabled).to.equal(true); + return done();}).catch(done); + }); + + return it('should catch errors', function(done) { + autoLaunchHelper.mockApi({ + enable() { return Promise.reject(); }}); + + autoLaunch.enable().catch(done); + }); + }); + + + describe('.disable', function() { + beforeEach(() => autoLaunchHelper.ensureEnabled()); + + it('should disable auto launch', function(done) { + autoLaunch.disable() + .then(() => autoLaunch.isEnabled()) + .then(function(enabled) { + expect(enabled).to.equal(false); + return done();}) + .catch(done); + }); + + return it('should catch errors', function(done) { + autoLaunchHelper.mockApi({ + disable() { + return Promise.reject(); + } + }); + + autoLaunch.disable().catch(done); + }); + }); + + + if (isLinux) { + describe('.appName', () => it('should honor name option', function(done) { + expect(autoLaunch.opts.appName).to.equal('node-auto-launch test'); + done(); + })); + + describe('testing path name', function() { + const executablePathLinux = path.resolve('./path with spaces/'); + const autoLaunchLinux = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePathLinux + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux); + + return it('should properly escape reserved caracters', function(done) { + expect(autoLaunchLinux.opts.appPath).not.to.equal(executablePathLinux); + done(); + }); + }); + } + } + + + // Let's test some Mac-only options + if (!isMac) { return; } + + return describe('mac.useLaunchAgent', function() { + let autoLaunchWithLaunchAgent = null; + let autoLaunchWithLaunchAgentHelper = null; + + beforeEach(function() { + autoLaunchWithLaunchAgent = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath, + mac: { + useLaunchAgent: true + } + }); + return autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); + }); + + describe('.isEnabled', function() { + beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + + it('should be disabled', function(done) { + autoLaunchWithLaunchAgent.isEnabled().then(function(enabled) { + expect(enabled).to.equal(false); + return done();}).catch(done); + }); + + return it('should catch errors', function(done) { + autoLaunchWithLaunchAgentHelper.mockApi({ + isEnabled() { return Promise.reject(); }}); + + autoLaunchWithLaunchAgent.isEnabled().catch(done); + }); + }); + + + describe('.enable', function() { + beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + + it('should enable auto launch', function(done) { + autoLaunchWithLaunchAgent.enable().then(() => autoLaunchWithLaunchAgent.isEnabled().then(function(enabled) { + expect(enabled).to.equal(true); + return done(); + })).catch(done); + }); + + return it('should catch errors', function(done) { + autoLaunchWithLaunchAgentHelper.mockApi({ + enable() { return Promise.reject(); }}); + + autoLaunchWithLaunchAgent.enable().catch(done); + }); + }); + + + return describe('.disable', function() { + beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureEnabled()); + + it('should disable auto launch', function(done) { + autoLaunchWithLaunchAgent.disable() + .then(() => autoLaunchWithLaunchAgent.isEnabled()) + .then(function(enabled) { + expect(enabled).to.equal(false); + return done();}).catch(done); + }); + + return it('should catch errors', function(done) { + autoLaunchWithLaunchAgentHelper.mockApi({ + disable() { return Promise.reject(); }}); + + autoLaunchWithLaunchAgent.disable().catch(done); + }); + }); + }); +}); From 002218d5f2110ffbda721ce268cfffe3ea14e2a6 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 18 Dec 2023 20:25:25 -0500 Subject: [PATCH 02/77] Fix babel/eslint scripts Signed-off-by: Alexandre Demers --- .eslintrc.json | 3 ++- package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 316e980..7affef3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,8 +4,9 @@ "browser": true, "mocha": true }, - "parser": "babel-eslint", + "parser": "@babel/eslint-parser", "parserOptions": { + "requireConfigFile": false, "sourceType": "module" }, "rules": { diff --git a/package.json b/package.json index 9478e50..d326df9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "main": "dist/index.js", "scripts": { - "lint": "eslint --ext .ts src script test", + "lint": "eslint --ext .js src tests", "lint:fix": "pnpm lint --fix", "test": "mocha tests/**/*.js --reporter spec" }, @@ -37,6 +37,7 @@ "url": "https://github.com/4ver/node-auto-launch/issues" }, "devDependencies": { + "@babel/core": "^7.23.6", "@babel/eslint-parser": "^7.23.0", "chai": "^3.5.0", "eslint": "^8.55.0", From c89f792e3cc5d6522f604d77765eba19772b1fac Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 18 Dec 2023 22:59:37 -0500 Subject: [PATCH 03/77] Fix Linux import of untildify Signed-off-by: Alexandre Demers --- src/AutoLaunchLinux.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/AutoLaunchLinux.js b/src/AutoLaunchLinux.js index 42b1525..54288fc 100644 --- a/src/AutoLaunchLinux.js +++ b/src/AutoLaunchLinux.js @@ -1,4 +1,5 @@ -const untildify = require('untildify'); +import {untildify} from 'untildify'; + const fileBasedUtilities = require('./fileBasedUtilities'); module.exports = { @@ -48,4 +49,4 @@ Terminal=false`; // appName - {String} // Returns a {String} getFilePath(appName) { return `${this.getDirectory()}${appName.toLowerCase()}.desktop`; } -}; \ No newline at end of file +}; From 715d0974e55871ad408a067bb3ac2e57e9765325 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 14:30:54 -0500 Subject: [PATCH 04/77] Improve our editor tools' configuration: editorconfig, babel and eslint Signed-off-by: Alexandre Demers --- .babelrc | 3 +++ .editorconfig | 8 +++++++- .eslintrc.json | 15 +++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 .babelrc diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..d3337dc --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": [ "@babel/preset-env" ] +} diff --git a/.editorconfig b/.editorconfig index b9bbff5..8a2b8e1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,10 +4,16 @@ root = true [*] -charset = "utf8" +charset = "utf-8" +indent_style = space +indent_size = 4 +end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true +[{package.json,package-lock.json}] +indent_size = 2 + [*.js] indent_style = space indent_size = 4 diff --git a/.eslintrc.json b/.eslintrc.json index 7affef3..af67599 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,6 +10,17 @@ "sourceType": "module" }, "rules": { - "class-methods-use-this": 0 + "brace-style": "warn", + "class-methods-use-this": 0, + "comma-dangle": ["warn", "only-multiline"], + "indent": ["warn", 4, { "SwitchCase": 1 }], + "lines-between-class-members": "off", + "max-len": ["warn", 128], + "no-var": "error", + "no-useless-constructor": "off", + "object-curly-newline": "warn", + "object-curly-spacing": "warn", + "prefer-arrow-callback": "off", + "prefer-destructuring": "off" } -} \ No newline at end of file +} From 193ed54a7e4e285d07a0a163ebc5015ef2712d3e Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 14:32:41 -0500 Subject: [PATCH 05/77] Update package.json Some urls and dependencies need to be updated. Signed-off-by: Alexandre Demers --- package.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d326df9..cad375b 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/4ver/node-auto-launch" + "url": "https://github.com/Teamwork/node-auto-launch" }, "keywords": [ "login", @@ -32,20 +32,21 @@ "contributors": [ "Adam Lynch " ], + "homepage": "https://github.com/Teamwork/node-auto-launch", "license": "MIT", "bugs": { - "url": "https://github.com/4ver/node-auto-launch/issues" + "url": "https://github.com/Teamwork/node-auto-launch/issues" }, "devDependencies": { "@babel/core": "^7.23.6", "@babel/eslint-parser": "^7.23.0", - "chai": "^3.5.0", + "@babel/preset-env": "^7.23.6", + "chai": "^4.3.0", "eslint": "^8.55.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.29.0", - "mocha": "^4.0.0" + "mocha": "^10.2.0" }, - "homepage": "https://github.com/4ver/node-auto-launch", "dependencies": { "applescript": "^1.0.0", "mkdirp": "^3.0.0", From 20543e86b8bf2ca76163be3135788ef5fcd75aa5 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 14:36:02 -0500 Subject: [PATCH 06/77] Package.json: set ES module Our code will now have to use ES module coding style. Signed-off-by: Alexandre Demers --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index cad375b..0874194 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,9 @@ "name": "auto-launch", "version": "5.0.6", "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", - "main": "dist/index.js", + "type": "module", + "main": "./src/index.js", + "exports": "./src/index.js", "scripts": { "lint": "eslint --ext .js src tests", "lint:fix": "pnpm lint --fix", From c05575198941a372acf110250fb797df4ed142f2 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 15:16:26 -0500 Subject: [PATCH 07/77] Rewrite main module as ESM Signed-off-by: Alexandre Demers --- src/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index c879340..1969e04 100644 --- a/src/index.js +++ b/src/index.js @@ -4,12 +4,10 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md */ -let AutoLaunch; -const pathTools = require('path'); +import pathTools from 'path'; // Public: The main auto-launch class -module.exports = (AutoLaunch = class AutoLaunch { - +export default class AutoLaunch { /* Public */ // options - {Object} @@ -141,4 +139,4 @@ module.exports = (AutoLaunch = class AutoLaunch { } } } -}); \ No newline at end of file +} From d8c208f35e7bab200d77e496818678169072dca0 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 15:48:37 -0500 Subject: [PATCH 08/77] Add an API handler to instanciate the proper AutoLaunch subclass Introduce an API handler function which returns the right instance of AutoLaunch API implementation according to the platform it is running on. The API class and subclasses will be moved under their own folder in a latter commit, once we are ready to use this function. Signed-off-by: Alexandre Demers --- src/library/autoLaunchHandler.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/library/autoLaunchHandler.js diff --git a/src/library/autoLaunchHandler.js b/src/library/autoLaunchHandler.js new file mode 100644 index 0000000..a3bf850 --- /dev/null +++ b/src/library/autoLaunchHandler.js @@ -0,0 +1,23 @@ +import AutoLaunchAPILinux from './autoLaunchAPI/autoLaunchAPILinux.js'; +import AutoLaunchAPIMac from './autoLaunchAPI/autoLaunchAPIMac.js'; +import AutoLaunchAPIWindows from './autoLaunchAPI/autoLaunchAPIWindows.js'; + +/* This allows to select the AutoLaunch implementation specific to a */ +// +// Returns a AutoLaunchAPI object + +export default function autoLaunchHandler(options) { + let api; + + if (/^win/.test(process.platform)) { + api = new AutoLaunchAPIWindows(options); + } else if (/darwin/.test(process.platform)) { + api = new AutoLaunchAPIMac(options); + } else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { + api = new AutoLaunchAPILinux(options); + } else { + throw new Error('Unsupported platform'); + } + + return api; +} From 19569d30258ee8b653d25dc6e50f97cfd274139f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 22:33:24 -0500 Subject: [PATCH 09/77] AutoLaunch: fix mandatory name checkup An empty string was able to pass through. Catch all falsy values. Signed-off-by: Alexandre Demers --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 1969e04..dd11271 100644 --- a/src/index.js +++ b/src/index.js @@ -22,7 +22,8 @@ export default class AutoLaunch { this.disable = this.disable.bind(this); this.isEnabled = this.isEnabled.bind(this); this.fixOpts = this.fixOpts.bind(this); - if (name == null) { throw new Error('You must specify a name'); } + // Name is the only mandatory parameter and must neither be null nor empty + if (!name) { throw new Error('You must specify a name'); } this.opts = { appName: name, From 802a5f52f045b7017e29130feeb134a701767009 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 22:47:54 -0500 Subject: [PATCH 10/77] Change code to ES6 module, create class and subclasses for AutoLaunchAPI implementation Separate the code under a basic AutoLaunchAPI class and implement per platform child classes. This way, we can have specific code coherent with each platform, based on prior code. Since we are now working with classes, an instanciated object can refer to its own parameters using "this". Move the modules under library folder and its subfolder. Fix some more decaffeinated code. Signed-off-by: Alexandre Demers --- src/AutoLaunchLinux.js | 52 -------- src/AutoLaunchMac.js | 111 ------------------ src/AutoLaunchWindows.js | 84 ------------- src/fileBasedUtilities.js | 59 ---------- src/index.js | 52 +++----- src/library/autoLaunchAPI/autoLaunchAPI.js | 33 ++++++ .../autoLaunchAPI/autoLaunchAPILinux.js | 73 ++++++++++++ src/library/autoLaunchAPI/autoLaunchAPIMac.js | 108 +++++++++++++++++ .../autoLaunchAPI/autoLaunchAPIWindows.js | 103 ++++++++++++++++ src/library/fileBasedUtilities.js | 53 +++++++++ 10 files changed, 389 insertions(+), 339 deletions(-) delete mode 100644 src/AutoLaunchLinux.js delete mode 100644 src/AutoLaunchMac.js delete mode 100644 src/AutoLaunchWindows.js delete mode 100644 src/fileBasedUtilities.js create mode 100644 src/library/autoLaunchAPI/autoLaunchAPI.js create mode 100644 src/library/autoLaunchAPI/autoLaunchAPILinux.js create mode 100644 src/library/autoLaunchAPI/autoLaunchAPIMac.js create mode 100644 src/library/autoLaunchAPI/autoLaunchAPIWindows.js create mode 100644 src/library/fileBasedUtilities.js diff --git a/src/AutoLaunchLinux.js b/src/AutoLaunchLinux.js deleted file mode 100644 index 54288fc..0000000 --- a/src/AutoLaunchLinux.js +++ /dev/null @@ -1,52 +0,0 @@ -import {untildify} from 'untildify'; - -const fileBasedUtilities = require('./fileBasedUtilities'); - -module.exports = { - - /* Public */ - - // options - {Object} - // :appName - {String} - // :appPath - {String} - // :isHiddenOnLaunch - {Boolean} - // Returns a Promise - enable({appName, appPath, isHiddenOnLaunch}) { - const hiddenArg = isHiddenOnLaunch ? '--hidden' : ''; - - const data = `[Desktop Entry] -Type=Application -Version=1.0 -Name=${appName} -Comment=${appName} startup script -Exec=${appPath} ${hiddenArg} -StartupNotify=false -Terminal=false`; - - return fileBasedUtilities.createFile({ - data, - directory: this.getDirectory(), - filePath: this.getFilePath(appName.toLowerCase()) - }); - }, - - - // appName - {String} - // Returns a Promise - disable(appName) { return fileBasedUtilities.removeFile(this.getFilePath(appName.toLowerCase())); }, - - - // appName - {String} - // Returns a Promise which resolves to a {Boolean} - isEnabled(appName) { return fileBasedUtilities.isEnabled(this.getFilePath(appName.toLowerCase())); }, - - - /* Private */ - - // Returns a {String} - getDirectory() { return untildify('~/.config/autostart/'); }, - - // appName - {String} - // Returns a {String} - getFilePath(appName) { return `${this.getDirectory()}${appName.toLowerCase()}.desktop`; } -}; diff --git a/src/AutoLaunchMac.js b/src/AutoLaunchMac.js deleted file mode 100644 index 2cb6784..0000000 --- a/src/AutoLaunchMac.js +++ /dev/null @@ -1,111 +0,0 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ -const applescript = require('applescript'); -const untildify = require('untildify'); -const fileBasedUtilities = require('./fileBasedUtilities'); - - -module.exports = { - - /* Public */ - - // options - {Object} - // :appName - {String} - // :appPath - {String} - // :isHiddenOnLaunch - {Boolean} - // :mac - (Optional) {Object} - // :useLaunchAgent - (Optional) {Boolean} - // Returns a Promise - enable({appName, appPath, isHiddenOnLaunch, mac}) { - - // Add the file if we're using a Launch Agent - if (mac.useLaunchAgent) { - const programArguments = [appPath]; - if (isHiddenOnLaunch) { programArguments.push('--hidden'); } - const programArgumentsSection = programArguments - .map(argument => ` ${argument}`) - .join('\n'); - - const data = ` - - - - Label - ${appName} - ProgramArguments - - ${programArgumentsSection} - - RunAtLoad - - -`; - - return fileBasedUtilities.createFile({ - data, - directory: this.getDirectory(), - filePath: this.getFilePath(appName) - }); - } - - // Otherwise, use default method; use AppleScript to tell System Events to add a Login Item - - const isHiddenValue = isHiddenOnLaunch ? 'true' : 'false'; - const properties = `{path:\"${appPath}\", hidden:${isHiddenValue}, name:\"${appName}\"}`; - - return this.execApplescriptCommand(`make login item at end with properties ${properties}`); - }, - - - // appName - {String} - // mac - {Object} - // :useLaunchAgent - {Object} - // Returns a Promise - disable(appName, mac) { - // Delete the file if we're using a Launch Agent - if (mac.useLaunchAgent) { return fileBasedUtilities.removeFile(this.getFilePath(appName)); } - - // Otherwise remove the Login Item - return this.execApplescriptCommand(`delete login item \"${appName}\"`); - }, - - - // appName - {String} - // mac - {Object} - // :useLaunchAgent - {Object} - // Returns a Promise which resolves to a {Boolean} - isEnabled(appName, mac) { - // Check if the Launch Agent file exists - if (mac.useLaunchAgent) { return fileBasedUtilities.isEnabled(this.getFilePath(appName)); } - - // Otherwise check if a Login Item exists for our app - return this.execApplescriptCommand('get the name of every login item').then(loginItems => (loginItems != null) && Array.from(loginItems).includes(appName)); - }, - - - /* Private */ - - - // commandSuffix - {String} - // Returns a Promise - execApplescriptCommand(commandSuffix) { - return new Promise((resolve, reject) => applescript.execString(`tell application \"System Events\" to ${commandSuffix}`, function(err, result) { - if (err != null) { return reject(err); } - return resolve(result); - })); - }, - - - // Returns a {String} - getDirectory() { return untildify('~/Library/LaunchAgents/'); }, - - - // appName - {String} - // Returns a {String} - getFilePath(appName) { return `${this.getDirectory()}${appName}.plist`; } -}; \ No newline at end of file diff --git a/src/AutoLaunchWindows.js b/src/AutoLaunchWindows.js deleted file mode 100644 index c1b680b..0000000 --- a/src/AutoLaunchWindows.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ -const fs = require('fs'); -const path = require('path'); -const winreg = require('winreg'); - - -const 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(function(resolve, reject) { - // 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 - let args = ''; - let pathToAutoLaunchedApp; - const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe'); - - if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) { - pathToAutoLaunchedApp = `\"${updateDotExe}\"`; - args = ` --processStart \"${path.basename(process.execPath)}\"`; - if (isHiddenOnLaunch) { args += ' --process-start-args "--hidden"'; } - } else { - // 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 != null) { - pathToAutoLaunchedApp = `\"explorer.exe\" shell:AppsFolder\\${appPath}`; - } else { - pathToAutoLaunchedApp = `\"${appPath}\"`; - } - if (isHiddenOnLaunch) { args = ' --hidden'; } - } - - return regKey.set(appName, winreg.REG_SZ, `${pathToAutoLaunchedApp}${args}`, function(err) { - if (err != null) { return reject(err); } - return resolve(); - }); - }); - }, - - - // appName - {String} - // Returns a Promise - disable(appName) { - return new Promise((resolve, reject) => regKey.remove(appName, function(err) { - if (err != null) { - // 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') !== -1) { - return resolve(false); - } - return reject(err); - } - return resolve(); - })); - }, - - - // appName - {String} - // Returns a Promise which resolves to a {Boolean} - isEnabled(appName) { - return new Promise((resolve, reject) => regKey.get(appName, function(err, item) { - if (err != null) { return resolve(false); } - return resolve(item != null); - })); - } -}; diff --git a/src/fileBasedUtilities.js b/src/fileBasedUtilities.js deleted file mode 100644 index 6ba7056..0000000 --- a/src/fileBasedUtilities.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ -const fs = require('fs'); -const mkdirp = require('mkdirp'); - -// Public: a few utils for file-based auto-launching -module.exports = { - - /* Public */ - - // This is essentially enabling auto-launching - // options - {Object} - // :data - {String} - // :directory - {String} - // :filePath - {String} - // Returns a Promise - createFile({directory, filePath, data}) { - return new Promise((resolve, reject) => mkdirp(directory, function(mkdirErr) { - if (mkdirErr != null) { return reject(mkdirErr); } - return fs.writeFile(filePath, data, function(writeErr) { - if (writeErr != null) { return reject(writeErr); } - return resolve(); - }); - })); - }, - - - // filePath - {String} - isEnabled(filePath) { - return new Promise((resolve, reject) => { - return fs.stat(filePath, function(err, stat) { - if (err != null) { return resolve(false); } - return resolve(stat != null); - }); - }); - }, - - - // This is essentially disabling auto-launching - // filePath - {String} - // Returns a Promise - removeFile(filePath) { - return new Promise((resolve, reject) => { - return fs.stat(filePath, function(statErr) { - // If it doesn't exist, this is good so resolve - if (statErr != null) { return resolve(); } - - return fs.unlink(filePath, function(unlinkErr) { - if (unlinkErr != null) { return reject(unlinkErr); } - return resolve(); - }); - }); - }); - } -}; \ No newline at end of file diff --git a/src/index.js b/src/index.js index dd11271..d190a21 100644 --- a/src/index.js +++ b/src/index.js @@ -5,30 +5,32 @@ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md */ import pathTools from 'path'; +import autoLaunchHandler from './library/autoLaunchHandler.js' // Public: The main auto-launch class export default class AutoLaunch { /* Public */ - // options - {Object} - // :name - {String} - // :isHidden - (Optional) {Boolean} - // :mac - (Optional) {Object} - // :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript + // {Object} + // :appName - {String} + // :execPath - (Optional) {String} + // :options - (Optional) {Object} + // :launchInBackground, - (Optional) {String}. If set, either use default --hidden arg or specified one. + // :mac - (Optional) {Object} + // :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript // to add Login Item - // :path - (Optional) {String} - constructor({name, isHidden, mac, path}) { - this.enable = this.enable.bind(this); - this.disable = this.disable.bind(this); - this.isEnabled = this.isEnabled.bind(this); - this.fixOpts = this.fixOpts.bind(this); + // :extraArgs - (Optional) {Array} + constructor({ name, path, options}) { // Name is the only mandatory parameter and must neither be null nor empty if (!name) { throw new Error('You must specify a name'); } this.opts = { appName: name, - isHiddenOnLaunch: (isHidden != null) ? isHidden : false, - mac: mac != null ? mac : {} + options: { + launchInBackground: (options.launchInBackground != null) ? options.launchInBackground : false, + mac: (options.mac != null) ? options.mac : {}, + extraArguments: (options.extraArguments != null) ? options.extraArgs : [] + } }; const versions = typeof process !== 'undefined' && process !== null ? process.versions : undefined; @@ -36,43 +38,27 @@ export default class AutoLaunch { // Verify that the path is absolute if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { throw new Error('path must be absolute'); } this.opts.appPath = path; - } else if ((versions != null) && ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) { // This appPath will need to be fixed later depending of the OS used this.opts.appPath = process.execPath; - } else { throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); } this.fixOpts(); - this.api = null; - if (/^win/.test(process.platform)) { - this.api = require('./AutoLaunchWindows'); - } else if (/darwin/.test(process.platform)) { - this.api = require('./AutoLaunchMac'); - } else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - this.api = require('./AutoLaunchLinux'); - } else { - throw new Error('Unsupported platform'); - } + this.api = autoLaunchHandler(this.opts); } + enable() { return this.api.enable(); } - enable() { return this.api.enable(this.opts); } - - - disable() { return this.api.disable(this.opts.appName, this.opts.mac); } - + disable() { return this.api.disable(); } // Returns a Promise which resolves to a {Boolean} - isEnabled() { return this.api.isEnabled(this.opts.appName, this.opts.mac); } - + isEnabled() { return this.api.isEnabled(); } /* Private */ - // Corrects the path to point to the outer .app // path - {String} // macOptions - {Object} diff --git a/src/library/autoLaunchAPI/autoLaunchAPI.js b/src/library/autoLaunchAPI/autoLaunchAPI.js new file mode 100644 index 0000000..7f0c5a3 --- /dev/null +++ b/src/library/autoLaunchAPI/autoLaunchAPI.js @@ -0,0 +1,33 @@ +export default class AutoLaunchAPI { + /* Public */ + + // init - {Object} + // :appName - {String} + // :appPath - {String} + // :options - {Object} + // :launchInBackground - (Optional) {String} If set, either use default --hidden arg or specified one. + // :mac - (Optional) {Object} + // :useLaunchAgent - (Optional) {Boolean} If `true`, use filed-based Launch Agent. Otherwise use AppleScript + // to add Login Item + // :extraArguments - (Optional) {Array} + constructor(init) { + this.appName = init.appName; + this.appPath = init.appPath; + this.options = init.options; + } + + // Returns a Promise + enable() { + throw new Error('enable() not implemented'); + } + + // Returns a Promise + disable() { + throw new Error('disable() not implemented'); + } + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + throw new Error('isEnable() not implemented'); + } +} diff --git a/src/library/autoLaunchAPI/autoLaunchAPILinux.js b/src/library/autoLaunchAPI/autoLaunchAPILinux.js new file mode 100644 index 0000000..19d76ba --- /dev/null +++ b/src/library/autoLaunchAPI/autoLaunchAPILinux.js @@ -0,0 +1,73 @@ +import untildify from 'untildify'; +import * as fileBasedUtilities from '../fileBasedUtilities.js'; +import AutoLaunchAPI from './autoLaunchAPI.js' + +const LINUX_AUTOSTART_DIR = '~/.config/autostart'; +const LINUX_DESKTOP = ` +[Desktop Entry] +Type=Application +Version=1.0 +Name={{APP_NAME}} +Comment={{APP_NAME}} startup script +Exec={{APP_PATH}} {{ARGS}} +StartupNotify=false +Terminal=false +`; + +export default class AutoLaunchAPILinux extends AutoLaunchAPI { + /* Public */ + + constructor(init) { + super(init); + } + + // Returns a Promise + enable() { + const hiddenArg = this.options.launchInBackground; + const extraArgs = this.options.extraArguments; + const programArguments = []; + + // Manage arguments + if (hiddenArg) { + programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden'); + } + if (extraArgs) { + programArguments.push(extraArgs); + } + const args = programArguments.join(' '); + + const desktop = LINUX_DESKTOP.trim() + .replace(/{{APP_NAME}}/g, this.appName) + .replace(/{{APP_PATH}}/g, this.appPath) + .replace(/{{ARGS}}/g, args); + + return fileBasedUtilities.createFile({ + directory: this.#getAutostartDirectory(), + filePath: this.#getDesktopFilePath(this.appName), + data: desktop + }); + } + + // Returns a Promise + disable() { + return fileBasedUtilities.removeFile(this.#getDesktopFilePath(this.appName)); + } + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + return fileBasedUtilities.fileExists(this.#getDesktopFilePath(this.appName)); + } + + /* Private */ + + // Returns a {String} + #getAutostartDirectory() { + return untildify(LINUX_AUTOSTART_DIR); + } + + // appName - {String} + // Returns a {String} + #getDesktopFilePath(appName) { + return `${this.#getAutostartDirectory()}${appName}.desktop`; + } +} diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js new file mode 100644 index 0000000..13b9d3c --- /dev/null +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -0,0 +1,108 @@ +import applescript from 'applescript'; +import untildify from 'untildify'; +import * as fileBasedUtilities from '../fileBasedUtilities.js'; +import AutoLaunchAPI from './autoLaunchAPI.js' + +const MAC_LAUNCHAGENTS_DIR = '~/Library/LaunchAgents/'; +const MAC_PLIST_DATA = ` + + + +Label +{{APP_NAME}} +ProgramArguments + +{{PROGRAM_ARGUMENTS_SECTION}} + +RunAtLoad + + +`; + +export default class AutoLaunchAPIMac extends AutoLaunchAPI { + /* Public */ + + constructor(init) { + super(init); + } + + // Returns a Promise + enable() { + const hiddenArg = this.options.launchInBackground; + const extraArgs = this.options.extraArguments; + + // Add the file if we're using a Launch Agent + if (this.mac.useLaunchAgent) { + const programArguments = this.appPath; + + // Manage arguments + if (hiddenArg) { + programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden'); + } + if (extraArgs) { + programArguments.push(extraArgs); + } + const programArgumentsSection = programArguments + .map((argument) => ` ${argument}`) + .join('\n'); + const plistData = MAC_PLIST_DATA.trim() + .replace(/{{APP_NAME}}/g, this.appName) + .replace(/{{PROGRAM_ARGUMENTS_SECTION}}/g, programArgumentsSection); + + return fileBasedUtilities.createFile({ + directory: this.#getLaunchAgentsDirectory(), + filePath: this.#getPlistFilePath(this.appName), + data: plistData + }); + } + + // Otherwise, use default method; use AppleScript to tell System Events to add a Login Item + + const isHidden = hiddenArg ? 'true' : 'false'; + // TODO: Manage extra arguments + const properties = `{path:"${this.appPath}", hidden:${isHidden}, name:"${this.appName}"}`; + + return this.#execApplescriptCommand(`make login item at end with properties ${properties}`); + } + + // Returns a Promise + disable() { + // Delete the file if we're using a Launch Agent + if (this.mac.useLaunchAgent) { return fileBasedUtilities.removeFile(this.#getPlistFilePath(this.appName)); } + + // Otherwise remove the Login Item + return this.#execApplescriptCommand(`delete login item "${this.appName}"`); + } + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + // Check if the Launch Agent file exists + if (this.mac.useLaunchAgent) { return fileBasedUtilities.fileExists(this.#getPlistFilePath(this.appName)); } + + // Otherwise check if a Login Item exists for our app + return this.#execApplescriptCommand('get the name of every login item') + .then((loginItems) => (loginItems != null) && Array.from(loginItems).includes(this.appName)); + } + + /* Private */ + + // commandSuffix - {String} + // Returns a Promise + #execApplescriptCommand(commandSuffix) { + return new Promise((resolve, reject) => { + applescript.execString(`tell application "System Events" to ${commandSuffix}`, (err, result) => { + if (err != null) { + return reject(err); + } + return resolve(result); + }) + }); + } + + // Returns a {String} + #getLaunchAgentsDirectory() { return untildify(MAC_LAUNCHAGENTS_DIR); } + + // appName - {String} + // Returns a {String} + #getPlistFilePath(appName) { return `${this.#getLaunchAgentsDirectory()}${appName}.plist`; } +} diff --git a/src/library/autoLaunchAPI/autoLaunchAPIWindows.js b/src/library/autoLaunchAPI/autoLaunchAPIWindows.js new file mode 100644 index 0000000..97cfd01 --- /dev/null +++ b/src/library/autoLaunchAPI/autoLaunchAPIWindows.js @@ -0,0 +1,103 @@ +import fs from 'fs'; +import path from 'path'; +import Winreg from 'winreg'; +import AutoLaunchAPI from './autoLaunchAPI.js' + +const regKey = new Winreg({ + hive: Winreg.HKCU, + key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' +}); + +export default class AutoLaunchAPIWindows extends AutoLaunchAPI { + /* Public */ + + constructor(init) { + super(init); + } + + // Returns a Promise + enable() { + return new Promise((resolve, reject) => { + // 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 + let args = ''; + let pathToAutoLaunchedApp; + const hiddenArg = this.options.launchInBackground; + const extraArgs = this.options.extraArguments; + const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe'); + + if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) { + pathToAutoLaunchedApp = `"${updateDotExe}"`; + args = ` --processStart "${path.basename(process.execPath)}"`; + + // Manage arguments + if (hiddenArg || extraArgs) { + args += ' --process-start-args'; + if (hiddenArg) { + args += ` "${(hiddenArg !== true) ? hiddenArg : '--hidden'}"`; + } + // Add any extra arguments + if (extraArgs) { + args += ' "'; + args += extraArgs.join('" "'); + args += '"'; + } + } + } else { + // 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 != null) { + pathToAutoLaunchedApp = `"explorer.exe" shell:AppsFolder\\${this.appPath}`; + } else { + pathToAutoLaunchedApp = `"${this.appPath}"`; + } + + // Manage arguments + if (hiddenArg) { args = [(hiddenArg !== true) ? hiddenArg : ' --hidden']; } + // Add any extra arguments + if (extraArgs) { + args += ' '; + args += extraArgs.join(' '); + } + } + + regKey.set(this.appName, Winreg.REG_SZ, `"${pathToAutoLaunchedApp}"${args}`, (err) => { + if (err != null) { + return reject(err); + } + return resolve(); + }); + }); + } + + // Returns a Promise + disable() { + return new Promise((resolve, reject) => { + regKey.remove(this.appName, (err) => { + if (err != null) { + // 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') !== -1) { + return resolve(false); + } + console.log(err.message); + return reject(err); + } + return resolve(); + }); + }); + } + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + return new Promise((resolve, reject) => { + regKey.valueExists(this.appName, (err, exists) => { + if (err != null) { + return resolve(false); + } + return resolve(exists); + }); + }); + } +} diff --git a/src/library/fileBasedUtilities.js b/src/library/fileBasedUtilities.js new file mode 100644 index 0000000..da4abc4 --- /dev/null +++ b/src/library/fileBasedUtilities.js @@ -0,0 +1,53 @@ +import fs from 'fs'; +import { mkdirp } from 'mkdirp'; + +// Public: a few utils for file-based auto-launching + +// This is essentially enabling auto-launching +// options - {Object} +// :directory - {String} +// :filePath - {String} +// :data - {String} +// Returns a Promise +export function createFile({directory, filePath, data}) { + return new Promise((resolve, reject) => { + mkdirp(directory, function(mkdirErr) { + if (mkdirErr != null) { return reject(mkdirErr); } + return fs.writeFile(filePath, data, function(writeErr) { + if (writeErr != null) { return reject(writeErr); } + return resolve(); + }); + }); + }); +} + +// Verify auto-launch file exists or not +// filePath - {String} +// Returns a Promise +export function fileExists(filePath) { + return new Promise((resolve, reject) => { + fs.stat(filePath, function(err, stat) { + if (err != null) { + return resolve(false); + } + return resolve(stat != null); + }); + }); +} + +// This is essentially disabling auto-launching +// filePath - {String} +// Returns a Promise +export function removeFile(filePath) { + return new Promise((resolve, reject) => { + fs.stat(filePath, function(statErr) { + // If it doesn't exist, this is good so resolve + if (statErr != null) { return resolve(); } + + return fs.unlink(filePath, function(unlinkErr) { + if (unlinkErr != null) { return reject(unlinkErr); } + return resolve(); + }); + }); + }); +} From 2556a2f1e08158dfd132816cb9327fc56ded3036 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 22:48:37 -0500 Subject: [PATCH 11/77] Update some comments and log Signed-off-by: Alexandre Demers --- src/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index d190a21..e9dd313 100644 --- a/src/index.js +++ b/src/index.js @@ -85,7 +85,7 @@ export default 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 != null) { path = process.env.APPIMAGE; - console.log("Using real AppImage path at: %s", 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. @@ -94,7 +94,6 @@ export default class AutoLaunch { return path; } - fixOpts() { let tempPath; this.opts.appPath = this.opts.appPath.replace(/\/$/, ''); @@ -107,7 +106,7 @@ export default class AutoLaunch { this.opts.appPath = this.fixLinuxExecPath(this.opts.appPath); } - // Comment: why are we fiddling with the appName while this is a mandatory when calling the constructor. + // Comment: why are we fiddling with the appName while this is mandatory when calling the constructor. // Shouldn't we honor the provided name? Windows use the name as a descriptor, macOS uses // it for naming the .plist file and Linux/FreeBSD use it to name the .desktop file. if (this.opts.appPath.indexOf('\\') !== -1) { From 188e72ffb8999c81363043557955cf2158c9261d Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:02:09 -0500 Subject: [PATCH 12/77] Make sure to return appName in all cases Signed-off-by: Alexandre Demers --- src/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index e9dd313..b2bbb07 100644 --- a/src/index.js +++ b/src/index.js @@ -110,7 +110,6 @@ export default class AutoLaunch { // Shouldn't we honor the provided name? Windows use the name as a descriptor, macOS uses // it for naming the .plist file and Linux/FreeBSD use it to name the .desktop file. if (this.opts.appPath.indexOf('\\') !== -1) { - tempPath = this.opts.appPath.split('\\'); this.opts.appName = tempPath[tempPath.length - 1]; this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.exe'.length); @@ -121,8 +120,10 @@ export default class AutoLaunch { this.opts.appName = tempPath[tempPath.length - 1]; // Remove ".app" from the appName if it exists if (this.opts.appName.indexOf('.app', this.opts.appName.length - '.app'.length) !== -1) { - return this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.app'.length); + this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.app'.length); } } + + return this.opts.appName; } } From c25a9d6b185c292b2aa1866d4889534932c24387 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:02:57 -0500 Subject: [PATCH 13/77] Remove decaffeinate comments Signed-off-by: Alexandre Demers --- src/index.js | 6 ------ tests/helper.js | 5 ----- tests/index.js | 5 ----- 3 files changed, 16 deletions(-) diff --git a/src/index.js b/src/index.js index b2bbb07..0ed2b38 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ import pathTools from 'path'; import autoLaunchHandler from './library/autoLaunchHandler.js' diff --git a/tests/helper.js b/tests/helper.js index bee342e..a9a9cb2 100644 --- a/tests/helper.js +++ b/tests/helper.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ let AutoLaunchHelper; module.exports = (AutoLaunchHelper = class AutoLaunchHelper { constructor(autoLaunch) { diff --git a/tests/index.js b/tests/index.js index 3697313..b3fcc85 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ let executablePath, isLinux; const chai = require('chai'); const path = require('path'); From d492a56c98954475c3e3b44456d56de9080e9bfe Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:07:46 -0500 Subject: [PATCH 14/77] Fix ternary "options" verification Signed-off-by: Alexandre Demers --- src/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 0ed2b38..bfb16c8 100644 --- a/src/index.js +++ b/src/index.js @@ -14,16 +14,16 @@ export default class AutoLaunch { // :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript // to add Login Item // :extraArgs - (Optional) {Array} - constructor({ name, path, options}) { + constructor({ name, path, options }) { // Name is the only mandatory parameter and must neither be null nor empty if (!name) { throw new Error('You must specify a name'); } this.opts = { appName: name, options: { - launchInBackground: (options.launchInBackground != null) ? options.launchInBackground : false, - mac: (options.mac != null) ? options.mac : {}, - extraArguments: (options.extraArguments != null) ? options.extraArgs : [] + launchInBackground: (options && (options.launchInBackground != null)) ? options.launchInBackground : false, + mac: (options && (options.mac != null)) ? options.mac : {}, + extraArguments: (options && (options.extraArguments != null)) ? options.extraArgs : [] } }; From e812375a0825502ad79756c9b036d03d4432154f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:11:07 -0500 Subject: [PATCH 15/77] Update tests for ESM and new code Fix some anonymous functions using "fat arrow" to access "this". Signed-off-by: Alexandre Demers --- package.json | 2 +- tests/helper.js | 22 +++-- tests/index.js | 221 ++++++++++++++++++++++++++---------------------- 3 files changed, 133 insertions(+), 112 deletions(-) diff --git a/package.json b/package.json index 0874194..17e3d4b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "lint": "eslint --ext .js src tests", "lint:fix": "pnpm lint --fix", - "test": "mocha tests/**/*.js --reporter spec" + "test": "mocha tests/index.js --reporter spec" }, "pre-commit": { "run": [ diff --git a/tests/helper.js b/tests/helper.js index a9a9cb2..a19f588 100644 --- a/tests/helper.js +++ b/tests/helper.js @@ -1,22 +1,28 @@ -let AutoLaunchHelper; -module.exports = (AutoLaunchHelper = class AutoLaunchHelper { +export default class AutoLaunchHelper { constructor(autoLaunch) { this.autoLaunch = autoLaunch; } ensureEnabled() { - return this.autoLaunch.isEnabled().then(enabled => { - if (!enabled) { return this.autoLaunch.enable(); } + return this.autoLaunch.isEnabled().then((enabled) => { + if (!enabled) { + return this.autoLaunch.enable(); + } + return enabled; }); } ensureDisabled() { - return this.autoLaunch.isEnabled().then(enabled => { - if (enabled) { return this.autoLaunch.disable(); } + return this.autoLaunch.isEnabled().then((enabled) => { + if (enabled) { + return this.autoLaunch.disable(); + } + return enabled; }); } mockApi(stubs) { - return this.autoLaunch.api = stubs; + this.autoLaunch.api = stubs; + return this.autoLaunch.api; } -}); +} diff --git a/tests/index.js b/tests/index.js index b3fcc85..3325d30 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,12 +1,10 @@ -let executablePath, isLinux; -const chai = require('chai'); -const path = require('path'); -const { - expect -} = chai; -const AutoLaunch = require('../src/'); -const AutoLaunchHelper = require('./helper'); +import { expect } from 'chai'; +import path from 'path'; +import AutoLaunch from '../src/index.js'; +import AutoLaunchHelper from './helper.js'; +let executablePath = ''; +let isPosix = false; let isMac = false; if (/^win/.test(process.platform)) { @@ -15,37 +13,41 @@ if (/^win/.test(process.platform)) { isMac = true; executablePath = '/Applications/Calculator.app'; } else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - isLinux = true; + isPosix = true; executablePath = path.resolve(path.join('./tests/executables', 'hv3-linux-x86')); } -console.log("Executable being used for tests:", executablePath); +console.log('Executable being used for tests:', executablePath); // General tests for all platforms -describe('node-auto-launch', function() { +describe('node-auto-launch', function () { let autoLaunch = null; let autoLaunchHelper = null; - - beforeEach(function() { + beforeEach(() => { autoLaunch = new AutoLaunch({ name: 'node-auto-launch test', path: executablePath }); - return autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + return autoLaunchHelper; }); if (!isMac) { - describe('.isEnabled', function() { - beforeEach(() => autoLaunchHelper.ensureDisabled()); + describe('.isEnabled', function () { + beforeEach(() => { + autoLaunchHelper.ensureDisabled(); + }); - it('should be disabled', function(done) { - autoLaunch.isEnabled().then(function(enabled) { - expect(enabled).to.equal(false); - return done();}).catch(done); + it('should be disabled', function (done) { + autoLaunch.isEnabled() + .then(function (enabled) { + expect(enabled).to.equal(false); + return done();}) + .catch(done); }); - return it('should catch errors', function(done) { + return it('should catch errors', function (done) { autoLaunchHelper.mockApi({ isEnabled() { return Promise.reject(); @@ -56,39 +58,48 @@ describe('node-auto-launch', function() { }); }); + describe('.enable', function () { + beforeEach(() => { + autoLaunchHelper.ensureDisabled(); + }); - describe('.enable', function() { - beforeEach(() => autoLaunchHelper.ensureDisabled()); - - it('should enable auto launch', function(done) { + it('should enable auto launch', function (done) { autoLaunch.enable() - .then(() => autoLaunch.isEnabled()).then(function(enabled) { - expect(enabled).to.equal(true); - return done();}).catch(done); + .then(() => autoLaunch.isEnabled()) + .then(function (enabled) { + expect(enabled).to.equal(true); + return done(); + }) + .catch(done); }); - return it('should catch errors', function(done) { + return it('should catch errors', function (done) { autoLaunchHelper.mockApi({ - enable() { return Promise.reject(); }}); + enable() { + return Promise.reject(); + } + }); autoLaunch.enable().catch(done); }); }); + describe('.disable', () => { + beforeEach(() => { + autoLaunchHelper.ensureEnabled(); + }); - describe('.disable', function() { - beforeEach(() => autoLaunchHelper.ensureEnabled()); - - it('should disable auto launch', function(done) { + it('should disable auto launch', function (done) { autoLaunch.disable() - .then(() => autoLaunch.isEnabled()) - .then(function(enabled) { - expect(enabled).to.equal(false); - return done();}) - .catch(done); + .then(() => autoLaunch.isEnabled()) + .then(function (enabled) { + expect(enabled).to.equal(false); + return done(); + }) + .catch(done); }); - return it('should catch errors', function(done) { + return it('should catch errors', function (done) { autoLaunchHelper.mockApi({ disable() { return Promise.reject(); @@ -99,14 +110,13 @@ describe('node-auto-launch', function() { }); }); - - if (isLinux) { - describe('.appName', () => it('should honor name option', function(done) { + if (isPosix) { + describe('.appName', () => it('should honor name option', function (done) { expect(autoLaunch.opts.appName).to.equal('node-auto-launch test'); done(); })); - describe('testing path name', function() { + describe('testing path name', function () { const executablePathLinux = path.resolve('./path with spaces/'); const autoLaunchLinux = new AutoLaunch({ name: 'node-auto-launch test', @@ -114,7 +124,7 @@ describe('node-auto-launch', function() { }); autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux); - return it('should properly escape reserved caracters', function(done) { + return it('should properly escape reserved caracters', function (done) { expect(autoLaunchLinux.opts.appPath).not.to.equal(executablePathLinux); done(); }); @@ -122,79 +132,84 @@ describe('node-auto-launch', function() { } } - // Let's test some Mac-only options - if (!isMac) { return; } - - return describe('mac.useLaunchAgent', function() { - let autoLaunchWithLaunchAgent = null; - let autoLaunchWithLaunchAgentHelper = null; - - beforeEach(function() { - autoLaunchWithLaunchAgent = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePath, - mac: { - useLaunchAgent: true - } - }); - return autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); - }); - - describe('.isEnabled', function() { - beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + else { + describe('mac.useLaunchAgent', function () { + let autoLaunchWithLaunchAgent = null; + let autoLaunchWithLaunchAgentHelper = null; - it('should be disabled', function(done) { - autoLaunchWithLaunchAgent.isEnabled().then(function(enabled) { - expect(enabled).to.equal(false); - return done();}).catch(done); + beforeEach(function () { + autoLaunchWithLaunchAgent = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath, + mac: { + useLaunchAgent: true + } + }); + autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); + return autoLaunchWithLaunchAgentHelper; }); - return it('should catch errors', function(done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - isEnabled() { return Promise.reject(); }}); - - autoLaunchWithLaunchAgent.isEnabled().catch(done); - }); - }); + describe('.isEnabled', function () { + beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + it('should be disabled', function (done) { + autoLaunchWithLaunchAgent.isEnabled() + .then(function (enabled) { + expect(enabled).to.equal(false); + return done();}) + .catch(done); + }); - describe('.enable', function() { - beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + return it('should catch errors', function (done) { + autoLaunchWithLaunchAgentHelper.mockApi({ + isEnabled() { return Promise.reject(); }}); - it('should enable auto launch', function(done) { - autoLaunchWithLaunchAgent.enable().then(() => autoLaunchWithLaunchAgent.isEnabled().then(function(enabled) { - expect(enabled).to.equal(true); - return done(); - })).catch(done); + autoLaunchWithLaunchAgent.isEnabled().catch(done); + }); }); - return it('should catch errors', function(done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - enable() { return Promise.reject(); }}); - - autoLaunchWithLaunchAgent.enable().catch(done); - }); - }); + describe('.enable', function () { + beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + it('should enable auto launch', function (done) { + autoLaunchWithLaunchAgent.enable() + .then(() => autoLaunchWithLaunchAgent.isEnabled().then(function (enabled) { + expect(enabled).to.equal(true); + return done(); + })) + .catch(done); + }); - return describe('.disable', function() { - beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureEnabled()); + return it('should catch errors', function (done) { + autoLaunchWithLaunchAgentHelper.mockApi({ + enable() { return Promise.reject(); }}); - it('should disable auto launch', function(done) { - autoLaunchWithLaunchAgent.disable() - .then(() => autoLaunchWithLaunchAgent.isEnabled()) - .then(function(enabled) { - expect(enabled).to.equal(false); - return done();}).catch(done); + autoLaunchWithLaunchAgent.enable().catch(done); + }); }); - return it('should catch errors', function(done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - disable() { return Promise.reject(); }}); + describe('.disable', function () { + beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureEnabled()); + + it('should disable auto launch', function (done) { + autoLaunchWithLaunchAgent.disable() + .then(() => autoLaunchWithLaunchAgent.isEnabled()) + .then(function (enabled) { + expect(enabled).to.equal(false); + return done(); + }) + .catch(done); + }); + + return it('should catch errors', function (done) { + autoLaunchWithLaunchAgentHelper.mockApi({ + disable() { return Promise.reject(); } + }); - autoLaunchWithLaunchAgent.disable().catch(done); + autoLaunchWithLaunchAgent.disable().catch(done); + }); }); }); - }); + } }); From 4f71c4f88f2b6f9fad4f8a7a85a3dbf552453f54 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:11:43 -0500 Subject: [PATCH 16/77] Update eslint with a few more options Signed-off-by: Alexandre Demers --- .eslintrc.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index af67599..3dd4276 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,11 +16,13 @@ "indent": ["warn", 4, { "SwitchCase": 1 }], "lines-between-class-members": "off", "max-len": ["warn", 128], + "no-promise-executor-return": "warn", "no-var": "error", "no-useless-constructor": "off", "object-curly-newline": "warn", "object-curly-spacing": "warn", "prefer-arrow-callback": "off", + "prefer-const": "warn", "prefer-destructuring": "off" } } From 554c51b762dbfeb380082fa78f13cfbf1621f4ab Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:16:38 -0500 Subject: [PATCH 17/77] tests: fix useLaunchAgent under options.mac The "mac" object has been relocated under "options" wirth the new API. Signed-off-by: Alexandre Demers --- tests/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/index.js b/tests/index.js index 3325d30..52f5ad1 100644 --- a/tests/index.js +++ b/tests/index.js @@ -142,8 +142,10 @@ describe('node-auto-launch', function () { autoLaunchWithLaunchAgent = new AutoLaunch({ name: 'node-auto-launch test', path: executablePath, - mac: { - useLaunchAgent: true + options: { + mac: { + useLaunchAgent: true + } } }); autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); From 86d22d2be2207a52107b145e460a9ad491e795ac Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:35:48 -0500 Subject: [PATCH 18/77] Bump node version dependency Technically, someone could use the --experimental-modules flag with nodejs version 12. But since we are going to bump the major version, we can upgrade our dependency requirements. Signed-off-by: Alexandre Demers --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17e3d4b..03ab140 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ ] }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "repository": { "type": "git", From c21337aff061d4b0e89535c1362aa06238f96247 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:36:40 -0500 Subject: [PATCH 19/77] Remove useless parameter in fixMacExecPath() Signed-off-by: Alexandre Demers --- src/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index bfb16c8..0149e09 100644 --- a/src/index.js +++ b/src/index.js @@ -55,7 +55,6 @@ export default class AutoLaunch { // Corrects the path to point to the outer .app // path - {String} - // macOptions - {Object} // Returns a {String} fixMacExecPath(path, macOptions) { // This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" @@ -93,7 +92,7 @@ export default class AutoLaunch { this.opts.appPath = this.opts.appPath.replace(/\/$/, ''); if (/darwin/.test(process.platform)) { - this.opts.appPath = this.fixMacExecPath(this.opts.appPath, this.opts.mac); + this.opts.appPath = this.fixMacExecPath(this.opts.appPath); } if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { From 9bc461beec6b7bbe215774086ead14c3a2abc2cd Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:39:45 -0500 Subject: [PATCH 20/77] Update .nvmrc to 14 Signed-off-by: Alexandre Demers --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 48082f7..8351c19 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12 +14 From 711dd699fd534fa8b503fb7db543c87134a860bc Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 28 Dec 2023 23:46:02 -0500 Subject: [PATCH 21/77] Remove node 12 from CI Signed-off-by: Alexandre Demers --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 72d689c..2efd44a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,7 +6,7 @@ jobs: strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] - node-version: ["12", "14", "16", "18", "20"] + node-version: ["14", "16", "18", "20"] runs-on: ${{ matrix.os }} From 83c8bd92fff7d6a6ef366ebdeaab0cd7a71c9dd0 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 29 Dec 2023 00:34:18 -0500 Subject: [PATCH 22/77] Linux/FreeBSD: move path correction directly in AutoLaunchAPI subclass This needs to be handled by and for Linux and FreeBSD specifically. It takes care of path when AppImage packages are used. It also escapes the path properly for its use in the Desktop entry file. Signed-off-by: Alexandre Demers --- src/index.js | 21 ------------------ .../autoLaunchAPI/autoLaunchAPILinux.js | 22 ++++++++++++++++--- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/index.js b/src/index.js index 0149e09..874db49 100644 --- a/src/index.js +++ b/src/index.js @@ -70,23 +70,6 @@ export default class AutoLaunch { return path; } - // Under Linux and FreeBSD, fix the ExecPath when packaged as AppImage and escape the spaces correctly - // path - {String} - // Returns a {String} - fixLinuxExecPath(path) { - // If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used. - // This will fail on the next launch, since AppImages are mount temporarily when executed in an everchanging mount folder. - if (process.env.APPIMAGE != null) { - 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'); - - return path; - } - fixOpts() { let tempPath; this.opts.appPath = this.opts.appPath.replace(/\/$/, ''); @@ -95,10 +78,6 @@ export default class AutoLaunch { this.opts.appPath = this.fixMacExecPath(this.opts.appPath); } - if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - this.opts.appPath = this.fixLinuxExecPath(this.opts.appPath); - } - // Comment: why are we fiddling with the appName while this is mandatory when calling the constructor. // Shouldn't we honor the provided name? Windows use the name as a descriptor, macOS uses // it for naming the .plist file and Linux/FreeBSD use it to name the .desktop file. diff --git a/src/library/autoLaunchAPI/autoLaunchAPILinux.js b/src/library/autoLaunchAPI/autoLaunchAPILinux.js index 19d76ba..6ef43a2 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPILinux.js +++ b/src/library/autoLaunchAPI/autoLaunchAPILinux.js @@ -1,3 +1,4 @@ +import path from 'node:path'; import untildify from 'untildify'; import * as fileBasedUtilities from '../fileBasedUtilities.js'; import AutoLaunchAPI from './autoLaunchAPI.js' @@ -19,6 +20,7 @@ export default class AutoLaunchAPILinux extends AutoLaunchAPI { constructor(init) { super(init); + this.appPath = this.#fixAppPath(); } // Returns a Promise @@ -65,9 +67,23 @@ export default class AutoLaunchAPILinux extends AutoLaunchAPI { return untildify(LINUX_AUTOSTART_DIR); } - // appName - {String} // Returns a {String} - #getDesktopFilePath(appName) { - return `${this.#getAutostartDirectory()}${appName}.desktop`; + #getDesktopFilePath() { + return path.join(this.#getAutostartDirectory(), `${this.appName}.desktop`); + } + + #fixAppPath() { + let execPath = this.appPath; + + // If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used. + // This will fail on the next launch, since AppImages are mount temporarily when executed + // in an everchanging mount folder. + if (process.env?.APPIMAGE != null) { + execPath = process.env.APPIMAGE; + } + + // As stated in the .desktop entry spec, Exec key's value must be properly escaped with reserved characters. + execPath = execPath.replace(/(\s+)/g, '\\$1'); + return execPath; } } From eed11c027df9fd94bc89342994e59cca9d5198ee Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 29 Dec 2023 02:43:24 -0500 Subject: [PATCH 23/77] Mac: move path correction directly in AutoLaunchAPI subclass This needs to be handled by and for macOS specifically. Signed-off-by: Alexandre Demers --- src/index.js | 31 ------------------ src/library/autoLaunchAPI/autoLaunchAPIMac.js | 32 +++++++++++++++++-- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/index.js b/src/index.js index 874db49..82a0613 100644 --- a/src/index.js +++ b/src/index.js @@ -53,39 +53,8 @@ export default class AutoLaunch { /* Private */ - // Corrects the path to point to the outer .app - // path - {String} - // Returns a {String} - fixMacExecPath(path, macOptions) { - // This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" - // (the default Electron app structure for example) - // It will also match apps whose outer app's basename is different to the rest but the inner app and executable's - // basenames are matching (a typical distributed NW.js app for example) - // Does not match when the three are different - // Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron - // executable in the outer app - path = path.replace(/(^.+?[^\/]+?\.app)\/Contents\/(Frameworks\/((\1|[^\/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1'); - // When using a launch agent, it needs the inner executable path - if (!macOptions.useLaunchAgent) { path = path.replace(/\.app\/Contents\/MacOS\/[^\/]*$/, '.app'); } - return path; - } - fixOpts() { let tempPath; - this.opts.appPath = this.opts.appPath.replace(/\/$/, ''); - - if (/darwin/.test(process.platform)) { - this.opts.appPath = this.fixMacExecPath(this.opts.appPath); - } - - // Comment: why are we fiddling with the appName while this is mandatory when calling the constructor. - // Shouldn't we honor the provided name? Windows use the name as a descriptor, macOS uses - // it for naming the .plist file and Linux/FreeBSD use it to name the .desktop file. - if (this.opts.appPath.indexOf('\\') !== -1) { - tempPath = this.opts.appPath.split('\\'); - this.opts.appName = tempPath[tempPath.length - 1]; - this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.exe'.length); - } if (/darwin/.test(process.platform)) { tempPath = this.opts.appPath.split('/'); diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index 13b9d3c..f453ac5 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -1,4 +1,5 @@ import applescript from 'applescript'; +import path from 'node:path'; import untildify from 'untildify'; import * as fileBasedUtilities from '../fileBasedUtilities.js'; import AutoLaunchAPI from './autoLaunchAPI.js' @@ -24,6 +25,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { constructor(init) { super(init); + this.appPath = this.#fixAppPath(); } // Returns a Promise @@ -100,9 +102,33 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { } // Returns a {String} - #getLaunchAgentsDirectory() { return untildify(MAC_LAUNCHAGENTS_DIR); } + #getLaunchAgentsDirectory() { + return untildify(MAC_LAUNCHAGENTS_DIR); + } + + // Returns a {String} + #getPlistFilePath() { + return path.join(this.#getLaunchAgentsDirectory(), `${this.appName}.plist`); + } - // appName - {String} + // Corrects the path to point to the outer .app // Returns a {String} - #getPlistFilePath(appName) { return `${this.#getLaunchAgentsDirectory()}${appName}.plist`; } + #fixAppPath() { + let execPath = this.appPath; + + // This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" + // (the default Electron app structure for example) + // It will also match apps whose outer app's basename is different to the rest but the inner app and executable's + // basenames are matching (a typical distributed NW.js app for example) + // Does not match when the three are different + // Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron + // executable in the outer app + execPath = execPath.replace(/(^.+?[^\/]+?\.app)\/Contents\/(Frameworks\/((\1|[^\/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1'); + + // When using a launch agent, it needs the inner executable path + if (!this.options.mac.useLaunchAgent) { + execPath = execPath.replace(/\.app\/Contents\/MacOS\/[^\/]*$/, '.app'); + } + return execPath; + } } From b1f47e15085ee342f5e29b6106b29172cf00c062 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 29 Dec 2023 02:47:43 -0500 Subject: [PATCH 24/77] Mac: fix options reading for mac specific options Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index f453ac5..abfc340 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -34,7 +34,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { const extraArgs = this.options.extraArguments; // Add the file if we're using a Launch Agent - if (this.mac.useLaunchAgent) { + if (this.options.mac.useLaunchAgent) { const programArguments = this.appPath; // Manage arguments @@ -70,7 +70,9 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { // Returns a Promise disable() { // Delete the file if we're using a Launch Agent - if (this.mac.useLaunchAgent) { return fileBasedUtilities.removeFile(this.#getPlistFilePath(this.appName)); } + if (this.options.mac.useLaunchAgent) { + return fileBasedUtilities.removeFile(this.#getPlistFilePath(this.appName)); + } // Otherwise remove the Login Item return this.#execApplescriptCommand(`delete login item "${this.appName}"`); @@ -79,7 +81,9 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { // Returns a Promise which resolves to a {Boolean} isEnabled() { // Check if the Launch Agent file exists - if (this.mac.useLaunchAgent) { return fileBasedUtilities.fileExists(this.#getPlistFilePath(this.appName)); } + if (this.options.mac.useLaunchAgent) { + return fileBasedUtilities.fileExists(this.#getPlistFilePath(this.appName)); + } // Otherwise check if a Login Item exists for our app return this.#execApplescriptCommand('get the name of every login item') From 51b7c0845e7a7eaca89192b449d85e71ccd58c90 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 29 Dec 2023 02:53:24 -0500 Subject: [PATCH 25/77] Mac: fix array declaration Can't push() without an array. Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index abfc340..b978f67 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -35,7 +35,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { // Add the file if we're using a Launch Agent if (this.options.mac.useLaunchAgent) { - const programArguments = this.appPath; + const programArguments = [this.appPath]; // Manage arguments if (hiddenArg) { From 15e83c2eccd305e6e67e09d2d013819dd520f82f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 17:52:29 -0500 Subject: [PATCH 26/77] Linux: remove parameters where not needed The instance knows about itself and can refer to its own parameters. Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPILinux.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPILinux.js b/src/library/autoLaunchAPI/autoLaunchAPILinux.js index 6ef43a2..9ff7ef5 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPILinux.js +++ b/src/library/autoLaunchAPI/autoLaunchAPILinux.js @@ -52,12 +52,12 @@ export default class AutoLaunchAPILinux extends AutoLaunchAPI { // Returns a Promise disable() { - return fileBasedUtilities.removeFile(this.#getDesktopFilePath(this.appName)); + return fileBasedUtilities.removeFile(this.#getDesktopFilePath()); } // Returns a Promise which resolves to a {Boolean} isEnabled() { - return fileBasedUtilities.fileExists(this.#getDesktopFilePath(this.appName)); + return fileBasedUtilities.fileExists(this.#getDesktopFilePath()); } /* Private */ From e37c562458f164ce413fd948e7bbe2927f72dff7 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 17:55:29 -0500 Subject: [PATCH 27/77] fileBasedUtilities: remove mkdirp's callback and using a then() In the decaffeination, it seems I mixed the mkdirp() call usage. No callback, but a then(). Clarify style because oneliner blocks are a hell to spot and read. Move anonymous "function" name to using "fat arrow" (leftovers). Signed-off-by: Alexandre Demers --- src/library/fileBasedUtilities.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/library/fileBasedUtilities.js b/src/library/fileBasedUtilities.js index da4abc4..69f3bea 100644 --- a/src/library/fileBasedUtilities.js +++ b/src/library/fileBasedUtilities.js @@ -11,13 +11,18 @@ import { mkdirp } from 'mkdirp'; // Returns a Promise export function createFile({directory, filePath, data}) { return new Promise((resolve, reject) => { - mkdirp(directory, function(mkdirErr) { - if (mkdirErr != null) { return reject(mkdirErr); } - return fs.writeFile(filePath, data, function(writeErr) { - if (writeErr != null) { return reject(writeErr); } - return resolve(); + mkdirp(directory) + .then((mkdirErr) => { + if (mkdirErr != null) { + return reject(mkdirErr); + } + return fs.writeFile(filePath, data, (writeErr) => { + if (writeErr != null) { + return reject(writeErr); + } + return resolve(); + }); }); - }); }); } @@ -26,7 +31,7 @@ export function createFile({directory, filePath, data}) { // Returns a Promise export function fileExists(filePath) { return new Promise((resolve, reject) => { - fs.stat(filePath, function(err, stat) { + fs.stat(filePath, (err, stat) => { if (err != null) { return resolve(false); } @@ -40,12 +45,16 @@ export function fileExists(filePath) { // Returns a Promise export function removeFile(filePath) { return new Promise((resolve, reject) => { - fs.stat(filePath, function(statErr) { + fs.stat(filePath, (statErr) => { // If it doesn't exist, this is good so resolve - if (statErr != null) { return resolve(); } + if (statErr != null) { + return resolve(); + } - return fs.unlink(filePath, function(unlinkErr) { - if (unlinkErr != null) { return reject(unlinkErr); } + return fs.unlink(filePath, (unlinkErr) => { + if (unlinkErr != null) { + return reject(unlinkErr); + } return resolve(); }); }); From 02b83bfcf0ac6123c85a2baf17048189c9f0d705 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 17:57:41 -0500 Subject: [PATCH 28/77] Tests: rework the test flow Move some anonymous "function" to using "fat arrow" (leftovers). Better class the tests between platforms. POSIX tests should be run on both Linux/FreeBSD and macOS platforms since they rely on writting and reading files on POSIX filesystems. Signed-off-by: Alexandre Demers --- tests/index.js | 247 ++++++++++++++++++++++++++++--------------------- 1 file changed, 140 insertions(+), 107 deletions(-) diff --git a/tests/index.js b/tests/index.js index 52f5ad1..6e1427f 100644 --- a/tests/index.js +++ b/tests/index.js @@ -20,34 +20,35 @@ if (/^win/.test(process.platform)) { console.log('Executable being used for tests:', executablePath); // General tests for all platforms -describe('node-auto-launch', function () { - let autoLaunch = null; - let autoLaunchHelper = null; - - beforeEach(() => { - autoLaunch = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePath +if (!isMac) { + describe('node-auto-launch', () => { + let autoLaunch = null; + let autoLaunchHelper = null; + + beforeEach(() => { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + return autoLaunchHelper; }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - return autoLaunchHelper; - }); - if (!isMac) { - describe('.isEnabled', function () { + describe('.isEnabled', () => { beforeEach(() => { autoLaunchHelper.ensureDisabled(); }); - it('should be disabled', function (done) { + it('should be disabled', (done) => { autoLaunch.isEnabled() - .then(function (enabled) { + .then((enabled) => { expect(enabled).to.equal(false); - return done();}) + return done(); + }) .catch(done); }); - return it('should catch errors', function (done) { + return it('should catch errors', (done) => { autoLaunchHelper.mockApi({ isEnabled() { return Promise.reject(); @@ -58,22 +59,24 @@ describe('node-auto-launch', function () { }); }); - describe('.enable', function () { + describe('.enable', () => { beforeEach(() => { autoLaunchHelper.ensureDisabled(); }); - it('should enable auto launch', function (done) { + it('should enable auto launch', (done) => { autoLaunch.enable() - .then(() => autoLaunch.isEnabled()) - .then(function (enabled) { - expect(enabled).to.equal(true); - return done(); + .then(() => { + autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(true); + return done(); + }); }) .catch(done); }); - return it('should catch errors', function (done) { + return it('should catch errors', (done) => { autoLaunchHelper.mockApi({ enable() { return Promise.reject(); @@ -89,17 +92,17 @@ describe('node-auto-launch', function () { autoLaunchHelper.ensureEnabled(); }); - it('should disable auto launch', function (done) { + it('should disable auto launch', (done) => { autoLaunch.disable() .then(() => autoLaunch.isEnabled()) - .then(function (enabled) { + .then((enabled) => { expect(enabled).to.equal(false); return done(); }) .catch(done); }); - return it('should catch errors', function (done) { + return it('should catch errors', (done) => { autoLaunchHelper.mockApi({ disable() { return Promise.reject(); @@ -109,109 +112,139 @@ describe('node-auto-launch', function () { autoLaunch.disable().catch(done); }); }); + }); +} + +// Let's test some POSIX/Linux/FreeBSD options +// They rely on reading and write files on POSIX based filesystems +if (isPosix || isMac) { + describe('POSIX/Linux/FreeBSD tests', () => { + let autoLaunchPosix = null; + // let autoLaunchPosixHelper = null; + const executablePathPosix = path.resolve('./path with spaces/'); + + beforeEach(() => { + autoLaunchPosix = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePathPosix, + options: { + mac: isMac ? { useLaunchAgent: true } : {} + } + }); + // autoLaunchPosixHelper = new AutoLaunchHelper(autoLaunchPosix); + }); - if (isPosix) { - describe('.appName', () => it('should honor name option', function (done) { - expect(autoLaunch.opts.appName).to.equal('node-auto-launch test'); + describe('.appName', () => { + it('should honor name option', (done) => { + expect(autoLaunchPosix.opts.appName).to.equal('node-auto-launch test'); done(); - })); - - describe('testing path name', function () { - const executablePathLinux = path.resolve('./path with spaces/'); - const autoLaunchLinux = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePathLinux - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunchLinux); + }); + }); - return it('should properly escape reserved caracters', function (done) { - expect(autoLaunchLinux.opts.appPath).not.to.equal(executablePathLinux); - done(); - }); + describe('testing path name', () => { + it('should properly escape reserved caracters', (done) => { + // console.log(autoLaunchPosix.appPath, ' VS ', executablePathPosix); + expect(autoLaunchPosix.appPath).not.to.equal(executablePathPosix); + done(); }); - } - } - - // Let's test some Mac-only options - else { - describe('mac.useLaunchAgent', function () { - let autoLaunchWithLaunchAgent = null; - let autoLaunchWithLaunchAgentHelper = null; - - beforeEach(function () { - autoLaunchWithLaunchAgent = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePath, - options: { - mac: { - useLaunchAgent: true - } + }); + }); +} + +// Let's test some Mac-only options +if (isMac) { + describe('mac.useLaunchAgent', () => { + let autoLaunchWithLaunchAgent = null; + let autoLaunchWithLaunchAgentHelper = null; + + beforeEach(() => { + autoLaunchWithLaunchAgent = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath, + options: { + mac: { + useLaunchAgent: true } - }); - autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); - return autoLaunchWithLaunchAgentHelper; + } }); + autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); + return autoLaunchWithLaunchAgentHelper; + }); - describe('.isEnabled', function () { - beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); - - it('should be disabled', function (done) { - autoLaunchWithLaunchAgent.isEnabled() - .then(function (enabled) { - expect(enabled).to.equal(false); - return done();}) - .catch(done); - }); + describe('.isEnabled', () => { + beforeEach(() => { + autoLaunchWithLaunchAgentHelper.ensureDisabled(); + }); - return it('should catch errors', function (done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - isEnabled() { return Promise.reject(); }}); + it('should be disabled', (done) => { + autoLaunchWithLaunchAgent.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); + return done(); + }) + .catch(done); + }); - autoLaunchWithLaunchAgent.isEnabled().catch(done); + return it('should catch errors', (done) => { + autoLaunchWithLaunchAgentHelper.mockApi({ + isEnabled() { + return Promise.reject(); + } }); + autoLaunchWithLaunchAgent.isEnabled().catch(done); }); + }); - describe('.enable', function () { - beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureDisabled()); + describe('.enable', () => { + beforeEach(() => { + autoLaunchWithLaunchAgentHelper.ensureDisabled(); + }); - it('should enable auto launch', function (done) { - autoLaunchWithLaunchAgent.enable() - .then(() => autoLaunchWithLaunchAgent.isEnabled().then(function (enabled) { + it('should enable auto launch', (done) => { + autoLaunchWithLaunchAgent.enable() + .then(() => autoLaunchWithLaunchAgent.isEnabled() + .then((enabled) => { expect(enabled).to.equal(true); return done(); })) - .catch(done); + .catch(done); + }); + + return it('should catch errors', (done) => { + autoLaunchWithLaunchAgentHelper.mockApi({ + enable() { + return Promise.reject(); + } }); - return it('should catch errors', function (done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - enable() { return Promise.reject(); }}); + autoLaunchWithLaunchAgent.enable().catch(done); + }); + }); - autoLaunchWithLaunchAgent.enable().catch(done); - }); + describe('.disable', () => { + beforeEach(() => { + autoLaunchWithLaunchAgentHelper.ensureEnabled(); }); - describe('.disable', function () { - beforeEach(() => autoLaunchWithLaunchAgentHelper.ensureEnabled()); + it('should disable auto launch', (done) => { + autoLaunchWithLaunchAgent.disable() + .then(() => autoLaunchWithLaunchAgent.isEnabled()) + .then((enabled) => { + expect(enabled).to.equal(false); + return done(); + }) + .catch(done); + }); - it('should disable auto launch', function (done) { - autoLaunchWithLaunchAgent.disable() - .then(() => autoLaunchWithLaunchAgent.isEnabled()) - .then(function (enabled) { - expect(enabled).to.equal(false); - return done(); - }) - .catch(done); + return it('should catch errors', (done) => { + autoLaunchWithLaunchAgentHelper.mockApi({ + disable() { + return Promise.reject(); + } }); - return it('should catch errors', function (done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - disable() { return Promise.reject(); } - }); - - autoLaunchWithLaunchAgent.disable().catch(done); - }); + autoLaunchWithLaunchAgent.disable().catch(done); }); }); - } -}); + }); +} From 6374081b30d1ba94e5a6fc1cd140e59ec3a0c089 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 18:15:51 -0500 Subject: [PATCH 29/77] test: there is no ".opts" member anymore Eventhough my local testing tells me otherwise when testing, there is no .opts member anymore. Signed-off-by: Alexandre Demers --- tests/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/index.js b/tests/index.js index 6e1427f..c72e167 100644 --- a/tests/index.js +++ b/tests/index.js @@ -136,7 +136,7 @@ if (isPosix || isMac) { describe('.appName', () => { it('should honor name option', (done) => { - expect(autoLaunchPosix.opts.appName).to.equal('node-auto-launch test'); + expect(autoLaunchPosix.appName).to.equal('node-auto-launch test'); done(); }); }); From bbe32564ba349e8d9b2271f4921a83aa6f08243b Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 18:26:21 -0500 Subject: [PATCH 30/77] mac: remove useless parameter Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index b978f67..9e6411c 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -53,7 +53,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { return fileBasedUtilities.createFile({ directory: this.#getLaunchAgentsDirectory(), - filePath: this.#getPlistFilePath(this.appName), + filePath: this.#getPlistFilePath(), data: plistData }); } @@ -71,7 +71,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { disable() { // Delete the file if we're using a Launch Agent if (this.options.mac.useLaunchAgent) { - return fileBasedUtilities.removeFile(this.#getPlistFilePath(this.appName)); + return fileBasedUtilities.removeFile(this.#getPlistFilePath()); } // Otherwise remove the Login Item @@ -82,7 +82,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { isEnabled() { // Check if the Launch Agent file exists if (this.options.mac.useLaunchAgent) { - return fileBasedUtilities.fileExists(this.#getPlistFilePath(this.appName)); + return fileBasedUtilities.fileExists(this.#getPlistFilePath()); } // Otherwise check if a Login Item exists for our app From 90660e83324ac620b5939b9b7fe3e67646ef4c6a Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 19:47:27 -0500 Subject: [PATCH 31/77] Clean up autoLaunchHandler Signed-off-by: Alexandre Demers --- src/library/autoLaunchHandler.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/library/autoLaunchHandler.js b/src/library/autoLaunchHandler.js index a3bf850..090dad8 100644 --- a/src/library/autoLaunchHandler.js +++ b/src/library/autoLaunchHandler.js @@ -7,17 +7,15 @@ import AutoLaunchAPIWindows from './autoLaunchAPI/autoLaunchAPIWindows.js'; // Returns a AutoLaunchAPI object export default function autoLaunchHandler(options) { - let api; - if (/^win/.test(process.platform)) { - api = new AutoLaunchAPIWindows(options); - } else if (/darwin/.test(process.platform)) { - api = new AutoLaunchAPIMac(options); - } else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - api = new AutoLaunchAPILinux(options); - } else { - throw new Error('Unsupported platform'); + return new AutoLaunchAPIWindows(options); + } + if (/darwin/.test(process.platform)) { + return new AutoLaunchAPIMac(options); + } + if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { + return new AutoLaunchAPILinux(options); } - return api; + throw new Error('Unsupported platform'); } From f60abb442aba15c74d63a13f9a7c2f1f8f4cfdc7 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 20:01:21 -0500 Subject: [PATCH 32/77] autoLaunch: really remove .opts member and fix tests I thought I had it removed, but I was wrong. Remove it from autoLaunch class. Move fixOpts() under private methods. Properly fix tests. Signed-off-by: Alexandre Demers --- src/index.js | 43 +++++++++++-------- .../autoLaunchAPI/autoLaunchAPILinux.js | 1 + tests/index.js | 4 +- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/index.js b/src/index.js index 82a0613..f47797a 100644 --- a/src/index.js +++ b/src/index.js @@ -6,8 +6,8 @@ export default class AutoLaunch { /* Public */ // {Object} - // :appName - {String} - // :execPath - (Optional) {String} + // :name - {String} + // :path - (Optional) {String} // :options - (Optional) {Object} // :launchInBackground, - (Optional) {String}. If set, either use default --hidden arg or specified one. // :mac - (Optional) {Object} @@ -18,7 +18,7 @@ export default class AutoLaunch { // Name is the only mandatory parameter and must neither be null nor empty if (!name) { throw new Error('You must specify a name'); } - this.opts = { + let opts = { appName: name, options: { launchInBackground: (options && (options.launchInBackground != null)) ? options.launchInBackground : false, @@ -31,40 +31,49 @@ export default class AutoLaunch { if (path != null) { // Verify that the path is absolute if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { throw new Error('path must be absolute'); } - this.opts.appPath = path; + opts.appPath = path; } else if ((versions != null) && ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) { // This appPath will need to be fixed later depending of the OS used - this.opts.appPath = process.execPath; + opts.appPath = process.execPath; } else { throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); } - this.fixOpts(); + opts = this.#fixOpts(opts); - this.api = autoLaunchHandler(this.opts); + this.api = autoLaunchHandler(opts); } - enable() { return this.api.enable(); } + enable() { + return this.api.enable(); + } - disable() { return this.api.disable(); } + disable() { + return this.api.disable(); + } // Returns a Promise which resolves to a {Boolean} - isEnabled() { return this.api.isEnabled(); } + isEnabled() { + return this.api.isEnabled(); + } /* Private */ - fixOpts() { - let tempPath; + #fixOpts(opts) { + const options = opts; if (/darwin/.test(process.platform)) { - tempPath = this.opts.appPath.split('/'); - this.opts.appName = tempPath[tempPath.length - 1]; + let name; + const tempPath = options.appPath.split('/'); + + name = tempPath[tempPath.length - 1]; // Remove ".app" from the appName if it exists - if (this.opts.appName.indexOf('.app', this.opts.appName.length - '.app'.length) !== -1) { - this.opts.appName = this.opts.appName.substr(0, this.opts.appName.length - '.app'.length); + if (name.indexOf('.app', name.length - '.app'.length) !== -1) { + name = name.substr(0, name.length - '.app'.length); } + options.appName = name; } - return this.opts.appName; + return options; } } diff --git a/src/library/autoLaunchAPI/autoLaunchAPILinux.js b/src/library/autoLaunchAPI/autoLaunchAPILinux.js index 9ff7ef5..98db574 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPILinux.js +++ b/src/library/autoLaunchAPI/autoLaunchAPILinux.js @@ -72,6 +72,7 @@ export default class AutoLaunchAPILinux extends AutoLaunchAPI { return path.join(this.#getAutostartDirectory(), `${this.appName}.desktop`); } + // Returns a {String} #fixAppPath() { let execPath = this.appPath; diff --git a/tests/index.js b/tests/index.js index c72e167..d55c9ae 100644 --- a/tests/index.js +++ b/tests/index.js @@ -136,7 +136,7 @@ if (isPosix || isMac) { describe('.appName', () => { it('should honor name option', (done) => { - expect(autoLaunchPosix.appName).to.equal('node-auto-launch test'); + expect(autoLaunchPosix.api.appName).to.equal('node-auto-launch test'); done(); }); }); @@ -144,7 +144,7 @@ if (isPosix || isMac) { describe('testing path name', () => { it('should properly escape reserved caracters', (done) => { // console.log(autoLaunchPosix.appPath, ' VS ', executablePathPosix); - expect(autoLaunchPosix.appPath).not.to.equal(executablePathPosix); + expect(autoLaunchPosix.api.appPath).not.to.equal(executablePathPosix); done(); }); }); From 1aca57074826a49d53c15dcc13573e4ce84e272c Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 20:27:01 -0500 Subject: [PATCH 33/77] autoLaunch - mac: move fixOpts to AutoLaunchAPIMac. The only remaining code is only applicable to macOS, so move the code under AutoLaunchAPIMac !?!?!? Still, do we need to fiddle the appName on macOS or should we honor what is given to us? Signed-off-by: Alexandre Demers --- src/index.js | 22 ------------------- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 18 +++++++++++++++ 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/index.js b/src/index.js index f47797a..2035e4d 100644 --- a/src/index.js +++ b/src/index.js @@ -39,8 +39,6 @@ export default class AutoLaunch { throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); } - opts = this.#fixOpts(opts); - this.api = autoLaunchHandler(opts); } @@ -56,24 +54,4 @@ export default class AutoLaunch { isEnabled() { return this.api.isEnabled(); } - - /* Private */ - - #fixOpts(opts) { - const options = opts; - - if (/darwin/.test(process.platform)) { - let name; - const tempPath = options.appPath.split('/'); - - name = tempPath[tempPath.length - 1]; - // Remove ".app" from the appName if it exists - if (name.indexOf('.app', name.length - '.app'.length) !== -1) { - name = name.substr(0, name.length - '.app'.length); - } - options.appName = name; - } - - return options; - } } diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index 9e6411c..95fd321 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -25,6 +25,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { constructor(init) { super(init); + this.appName = this.#fixAppName(); this.appPath = this.#fixAppPath(); } @@ -135,4 +136,21 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { } return execPath; } + + #fixAppName() { + let fixedName; + + // Kept from Coffeescript, but should we honor the name given to autoLaunch or should we change it for macOS? + if (/darwin/.test(process.platform)) { + const tempPath = this.appPath.split('/'); + + fixedName = tempPath[tempPath.length - 1]; + // Remove ".app" from the appName if it exists + if (fixedName.indexOf('.app', fixedName.length - '.app'.length) !== -1) { + fixedName = fixedName.substr(0, fixedName.length - '.app'.length); + } + } + + return fixedName; + } } From 25d5cbe622ca77f0513e22e063da220c611dee13 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 20:37:03 -0500 Subject: [PATCH 34/77] tests: rename index.js to test.js Easier to distinguish one from the other when both files are opened. Signed-off-by: Alexandre Demers --- package.json | 2 +- tests/{index.js => test.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{index.js => test.js} (100%) diff --git a/package.json b/package.json index 03ab140..0cfb748 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "lint": "eslint --ext .js src tests", "lint:fix": "pnpm lint --fix", - "test": "mocha tests/index.js --reporter spec" + "test": "mocha tests/test.js --reporter spec" }, "pre-commit": { "run": [ diff --git a/tests/index.js b/tests/test.js similarity index 100% rename from tests/index.js rename to tests/test.js From 1a1b4ec6fef82c155ee75b68efa0db4ed8957012 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 20:42:12 -0500 Subject: [PATCH 35/77] tests: CI catches a non-Error, let's try to fix it Signed-off-by: Alexandre Demers --- tests/test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test.js b/tests/test.js index d55c9ae..2b90d04 100644 --- a/tests/test.js +++ b/tests/test.js @@ -72,8 +72,7 @@ if (!isMac) { expect(enabled).to.equal(true); return done(); }); - }) - .catch(done); + }); }); return it('should catch errors', (done) => { From 4a70c3e989bec8359c73c792985a2614232b4328 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 20:45:37 -0500 Subject: [PATCH 36/77] tests: test appName honoring for both *nix and Windows Signed-off-by: Alexandre Demers --- tests/test.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/test.js b/tests/test.js index 2b90d04..8049461 100644 --- a/tests/test.js +++ b/tests/test.js @@ -111,6 +111,14 @@ if (!isMac) { autoLaunch.disable().catch(done); }); }); + + /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ + describe('.appName', () => { + it('should honor name parameter', (done) => { + expect(autoLaunch.api.appName).to.equal('node-auto-launch test'); + done(); + }); + }); }); } @@ -133,13 +141,6 @@ if (isPosix || isMac) { // autoLaunchPosixHelper = new AutoLaunchHelper(autoLaunchPosix); }); - describe('.appName', () => { - it('should honor name option', (done) => { - expect(autoLaunchPosix.api.appName).to.equal('node-auto-launch test'); - done(); - }); - }); - describe('testing path name', () => { it('should properly escape reserved caracters', (done) => { // console.log(autoLaunchPosix.appPath, ' VS ', executablePathPosix); From df12bb73093176764efa20f35d1e14c4f63e8ee0 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 20:49:18 -0500 Subject: [PATCH 37/77] tests: explicitly log the appPath value to debug under macOS I don't have access to a mac, but CI can tell me more... Signed-off-by: Alexandre Demers --- tests/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.js b/tests/test.js index 8049461..dd4f59e 100644 --- a/tests/test.js +++ b/tests/test.js @@ -143,7 +143,7 @@ if (isPosix || isMac) { describe('testing path name', () => { it('should properly escape reserved caracters', (done) => { - // console.log(autoLaunchPosix.appPath, ' VS ', executablePathPosix); + console.log(autoLaunchPosix.api.appPath, ' VS ', executablePathPosix); expect(autoLaunchPosix.api.appPath).not.to.equal(executablePathPosix); done(); }); From 02fdfa0e795744f60f77d8911162bdf5ff1dcfc6 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 21:19:23 -0500 Subject: [PATCH 38/77] tests: don't change escaped caracters in appPath on macOS We may not need it, at least we were not doing it under Coffeescript. Need to be verified. Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 1 + tests/test.js | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index 95fd321..a013d46 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -134,6 +134,7 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { if (!this.options.mac.useLaunchAgent) { execPath = execPath.replace(/\.app\/Contents\/MacOS\/[^\/]*$/, '.app'); } + return execPath; } diff --git a/tests/test.js b/tests/test.js index dd4f59e..7375431 100644 --- a/tests/test.js +++ b/tests/test.js @@ -72,7 +72,8 @@ if (!isMac) { expect(enabled).to.equal(true); return done(); }); - }); + }) + .catch(done); }); return it('should catch errors', (done) => { @@ -124,7 +125,7 @@ if (!isMac) { // Let's test some POSIX/Linux/FreeBSD options // They rely on reading and write files on POSIX based filesystems -if (isPosix || isMac) { +if (isPosix) { describe('POSIX/Linux/FreeBSD tests', () => { let autoLaunchPosix = null; // let autoLaunchPosixHelper = null; From f88f68839f9b334dd0c0e219273df5c62870946f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 22:43:19 -0500 Subject: [PATCH 39/77] FileBasedUtilities: add a function to escape special characters in filename It handles spaces, but some other characters could be targeted. Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPILinux.js | 3 ++- src/library/fileBasedUtilities.js | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPILinux.js b/src/library/autoLaunchAPI/autoLaunchAPILinux.js index 98db574..ad6e8b5 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPILinux.js +++ b/src/library/autoLaunchAPI/autoLaunchAPILinux.js @@ -84,7 +84,8 @@ export default class AutoLaunchAPILinux extends AutoLaunchAPI { } // As stated in the .desktop entry spec, Exec key's value must be properly escaped with reserved characters. - execPath = execPath.replace(/(\s+)/g, '\\$1'); + execPath = fileBasedUtilities.escapeFilePath(execPath); + return execPath; } } diff --git a/src/library/fileBasedUtilities.js b/src/library/fileBasedUtilities.js index 69f3bea..ea0abad 100644 --- a/src/library/fileBasedUtilities.js +++ b/src/library/fileBasedUtilities.js @@ -60,3 +60,9 @@ export function removeFile(filePath) { }); }); } + +// Escape reserved characters in path +export function escapeFilePath(filePath) { + filePath.replace(/(\s+)/g, '\\$1'); +// filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://github.com/tc39/proposal-regex-escaping +} From 396bd099dd8dc8f32424776d686dbe6fa47033f5 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 22:59:55 -0500 Subject: [PATCH 40/77] eslint: don't mess with linebreak style Signed-off-by: Alexandre Demers --- .eslintrc.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.json b/.eslintrc.json index 3dd4276..76ec1e8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,6 +15,7 @@ "comma-dangle": ["warn", "only-multiline"], "indent": ["warn", 4, { "SwitchCase": 1 }], "lines-between-class-members": "off", + "linebreak-style": "off", "max-len": ["warn", 128], "no-promise-executor-return": "warn", "no-var": "error", From fe267a80a4198fd7c9b2c981f6255c99ae8acd90 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 23:01:27 -0500 Subject: [PATCH 41/77] tests: will this fix the non-error reported under Linux in CI Still not reproducible on my machine, so I have to rely on CI. Signed-off-by: Alexandre Demers --- tests/test.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test.js b/tests/test.js index 7375431..6060de1 100644 --- a/tests/test.js +++ b/tests/test.js @@ -68,12 +68,13 @@ if (!isMac) { autoLaunch.enable() .then(() => { autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - return done(); - }); }) - .catch(done); + .then((enabled) => { + expect(enabled).to.equal(true); + return done(); + }); + }) + .catch(done); }); return it('should catch errors', (done) => { @@ -94,7 +95,9 @@ if (!isMac) { it('should disable auto launch', (done) => { autoLaunch.disable() - .then(() => autoLaunch.isEnabled()) + .then(() => { + autoLaunch.isEnabled(); + }) .then((enabled) => { expect(enabled).to.equal(false); return done(); From 6986f35f06ce5501954fb1684f8f891c218399a7 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 23:04:55 -0500 Subject: [PATCH 42/77] tests: missing ";" Signed-off-by: Alexandre Demers --- tests/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.js b/tests/test.js index 6060de1..b413520 100644 --- a/tests/test.js +++ b/tests/test.js @@ -67,7 +67,7 @@ if (!isMac) { it('should enable auto launch', (done) => { autoLaunch.enable() .then(() => { - autoLaunch.isEnabled() + autoLaunch.isEnabled(); }) .then((enabled) => { expect(enabled).to.equal(true); From ba384dd72b67f9ec745355f8a47d00cf89216011 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sat, 30 Dec 2023 23:22:29 -0500 Subject: [PATCH 43/77] tests: review our .then() and .catch() Tested under Windows and it's fine. Signed-off-by: Alexandre Demers --- tests/test.js | 57 ++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/tests/test.js b/tests/test.js index b413520..473884e 100644 --- a/tests/test.js +++ b/tests/test.js @@ -43,12 +43,12 @@ if (!isMac) { autoLaunch.isEnabled() .then((enabled) => { expect(enabled).to.equal(false); - return done(); + done(); }) .catch(done); }); - return it('should catch errors', (done) => { + it('should catch errors', (done) => { autoLaunchHelper.mockApi({ isEnabled() { return Promise.reject(); @@ -67,17 +67,16 @@ if (!isMac) { it('should enable auto launch', (done) => { autoLaunch.enable() .then(() => { - autoLaunch.isEnabled(); - }) - .then((enabled) => { - expect(enabled).to.equal(true); - return done(); + autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(true); + done(); + }) + .catch(done); }); - }) - .catch(done); }); - return it('should catch errors', (done) => { + it('should catch errors', (done) => { autoLaunchHelper.mockApi({ enable() { return Promise.reject(); @@ -96,16 +95,16 @@ if (!isMac) { it('should disable auto launch', (done) => { autoLaunch.disable() .then(() => { - autoLaunch.isEnabled(); - }) - .then((enabled) => { - expect(enabled).to.equal(false); - return done(); - }) - .catch(done); + autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); + done(); + }) + .catch(done); + }); }); - return it('should catch errors', (done) => { + it('should catch errors', (done) => { autoLaunchHelper.mockApi({ disable() { return Promise.reject(); @@ -184,12 +183,12 @@ if (isMac) { autoLaunchWithLaunchAgent.isEnabled() .then((enabled) => { expect(enabled).to.equal(false); - return done(); + done(); }) .catch(done); }); - return it('should catch errors', (done) => { + it('should catch errors', (done) => { autoLaunchWithLaunchAgentHelper.mockApi({ isEnabled() { return Promise.reject(); @@ -214,7 +213,7 @@ if (isMac) { .catch(done); }); - return it('should catch errors', (done) => { + it('should catch errors', (done) => { autoLaunchWithLaunchAgentHelper.mockApi({ enable() { return Promise.reject(); @@ -232,15 +231,17 @@ if (isMac) { it('should disable auto launch', (done) => { autoLaunchWithLaunchAgent.disable() - .then(() => autoLaunchWithLaunchAgent.isEnabled()) - .then((enabled) => { - expect(enabled).to.equal(false); - return done(); - }) - .catch(done); + .then(() => { + autoLaunchWithLaunchAgent.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); + done(); + }) + .catch(done); + }); }); - return it('should catch errors', (done) => { + it('should catch errors', (done) => { autoLaunchWithLaunchAgentHelper.mockApi({ disable() { return Promise.reject(); From a69db6592f18c78baeea5f1b60ccd6610b6370a7 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 01:22:04 -0500 Subject: [PATCH 44/77] test: another attemp to fix .enable() test under Linux Signed-off-by: Alexandre Demers --- tests/test.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/test.js b/tests/test.js index 473884e..c5f2640 100644 --- a/tests/test.js +++ b/tests/test.js @@ -66,14 +66,12 @@ if (!isMac) { it('should enable auto launch', (done) => { autoLaunch.enable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - done(); - }) - .catch(done); - }); + .then(() => autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(true); + done(); + })) + .catch(done); }); it('should catch errors', (done) => { @@ -208,7 +206,7 @@ if (isMac) { .then(() => autoLaunchWithLaunchAgent.isEnabled() .then((enabled) => { expect(enabled).to.equal(true); - return done(); + done(); })) .catch(done); }); From a6f09524ab113fe0228b76b82c3123f780a07741 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 02:01:52 -0500 Subject: [PATCH 45/77] tests: Linux is still getting a non-error in CI, but not local and not macOS Signed-off-by: Alexandre Demers --- tests/test.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/tests/test.js b/tests/test.js index c5f2640..2ac8cd8 100644 --- a/tests/test.js +++ b/tests/test.js @@ -66,11 +66,13 @@ if (!isMac) { it('should enable auto launch', (done) => { autoLaunch.enable() - .then(() => autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - done(); - })) + .then(() => { + autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(true); + done(); + }); + }) .catch(done); }); @@ -97,9 +99,9 @@ if (!isMac) { .then((enabled) => { expect(enabled).to.equal(false); done(); - }) - .catch(done); - }); + }); + }) + .catch(done); }); it('should catch errors', (done) => { @@ -203,11 +205,13 @@ if (isMac) { it('should enable auto launch', (done) => { autoLaunchWithLaunchAgent.enable() - .then(() => autoLaunchWithLaunchAgent.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - done(); - })) + .then(() => { + autoLaunchWithLaunchAgent.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(true); + done(); + }); + }) .catch(done); }); @@ -234,9 +238,9 @@ if (isMac) { .then((enabled) => { expect(enabled).to.equal(false); done(); - }) - .catch(done); - }); + }); + }) + .catch(done); }); it('should catch errors', (done) => { From 90f7a9c830049161b2fea1666962f65a6bc7e356 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 02:26:58 -0500 Subject: [PATCH 46/77] tests: POSIX, invert logic for escaping path with special characters Signed-off-by: Alexandre Demers --- tests/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test.js b/tests/test.js index 2ac8cd8..d958daa 100644 --- a/tests/test.js +++ b/tests/test.js @@ -146,8 +146,8 @@ if (isPosix) { describe('testing path name', () => { it('should properly escape reserved caracters', (done) => { - console.log(autoLaunchPosix.api.appPath, ' VS ', executablePathPosix); - expect(autoLaunchPosix.api.appPath).not.to.equal(executablePathPosix); + console.log(autoLaunchPosix.api.appPath, ' VS ', executablePathPosix.replace(/(\s+)/g, '\\$1')); + expect(autoLaunchPosix.api.appPath).equal.to(executablePathPosix.replace(/(\s+)/g, '\\$1')); done(); }); }); From 2e8c5db9aac4dafb7ed7dd82b1ce28a484d8f8b2 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 02:31:39 -0500 Subject: [PATCH 47/77] tests: fix expect() Signed-off-by: Alexandre Demers --- tests/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.js b/tests/test.js index d958daa..33b4972 100644 --- a/tests/test.js +++ b/tests/test.js @@ -147,7 +147,7 @@ if (isPosix) { describe('testing path name', () => { it('should properly escape reserved caracters', (done) => { console.log(autoLaunchPosix.api.appPath, ' VS ', executablePathPosix.replace(/(\s+)/g, '\\$1')); - expect(autoLaunchPosix.api.appPath).equal.to(executablePathPosix.replace(/(\s+)/g, '\\$1')); + expect(autoLaunchPosix.api.appPath).to.equal(executablePathPosix.replace(/(\s+)/g, '\\$1')); done(); }); }); From f16c59dd3e45fdacffb0f586dca701c990021a8c Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 03:14:46 -0500 Subject: [PATCH 48/77] tests: this may fix the linux case According to https://github.com/mochajs/mocha/issues/1187, this could be the solution. Signed-off-by: Alexandre Demers --- tests/test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test.js b/tests/test.js index 33b4972..9cd8df8 100644 --- a/tests/test.js +++ b/tests/test.js @@ -70,6 +70,9 @@ if (!isMac) { autoLaunch.isEnabled() .then((enabled) => { expect(enabled).to.equal(true); + // done(); + }) + .then(() => { done(); }); }) From 73481b1c34c54616faf3c83734a8d722675d0c72 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 03:18:20 -0500 Subject: [PATCH 49/77] tests: Could this be a better solution for Linux testcase Signed-off-by: Alexandre Demers --- tests/test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test.js b/tests/test.js index 9cd8df8..e81e471 100644 --- a/tests/test.js +++ b/tests/test.js @@ -71,11 +71,11 @@ if (!isMac) { .then((enabled) => { expect(enabled).to.equal(true); // done(); - }) - .then(() => { - done(); }); }) + .then(() => { + done(); + }) .catch(done); }); From c1c6326d844b31ba956f4cdd5e98cbba1f7cc19c Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Sun, 31 Dec 2023 04:56:05 -0500 Subject: [PATCH 50/77] fileBasedUtilities: add missing return escapeFilePath() was not returning a string. Remove console.log() calls now that they are not needed anymore. Signed-off-by: Alexandre Demers --- src/library/fileBasedUtilities.js | 6 ++++-- tests/test.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/library/fileBasedUtilities.js b/src/library/fileBasedUtilities.js index ea0abad..9c7b276 100644 --- a/src/library/fileBasedUtilities.js +++ b/src/library/fileBasedUtilities.js @@ -62,7 +62,9 @@ export function removeFile(filePath) { } // Escape reserved characters in path +// filePath - {String} +// Returns {String} export function escapeFilePath(filePath) { - filePath.replace(/(\s+)/g, '\\$1'); -// filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://github.com/tc39/proposal-regex-escaping + return filePath.replace(/(\s+)/g, '\\$1'); +// return filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://github.com/tc39/proposal-regex-escaping } diff --git a/tests/test.js b/tests/test.js index e81e471..181e258 100644 --- a/tests/test.js +++ b/tests/test.js @@ -73,6 +73,7 @@ if (!isMac) { // done(); }); }) + // This should prevent done() from catching non-errors .then(() => { done(); }) @@ -149,7 +150,6 @@ if (isPosix) { describe('testing path name', () => { it('should properly escape reserved caracters', (done) => { - console.log(autoLaunchPosix.api.appPath, ' VS ', executablePathPosix.replace(/(\s+)/g, '\\$1')); expect(autoLaunchPosix.api.appPath).to.equal(executablePathPosix.replace(/(\s+)/g, '\\$1')); done(); }); From 3ccfcad62490711b0aa8fa3575d30c073ed0cf7f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 1 Jan 2024 13:54:38 -0500 Subject: [PATCH 51/77] tests: revert to using "function" for anonymous callback function in "it()" As suggested by mochajs's documentation. Signed-off-by: Alexandre Demers --- tests/test.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/test.js b/tests/test.js index 181e258..d65461a 100644 --- a/tests/test.js +++ b/tests/test.js @@ -39,7 +39,7 @@ if (!isMac) { autoLaunchHelper.ensureDisabled(); }); - it('should be disabled', (done) => { + it('should be disabled', function (done) { autoLaunch.isEnabled() .then((enabled) => { expect(enabled).to.equal(false); @@ -48,7 +48,7 @@ if (!isMac) { .catch(done); }); - it('should catch errors', (done) => { + it('should catch errors', function (done) { autoLaunchHelper.mockApi({ isEnabled() { return Promise.reject(); @@ -80,7 +80,7 @@ if (!isMac) { .catch(done); }); - it('should catch errors', (done) => { + it('should catch errors', function (done) { autoLaunchHelper.mockApi({ enable() { return Promise.reject(); @@ -96,7 +96,7 @@ if (!isMac) { autoLaunchHelper.ensureEnabled(); }); - it('should disable auto launch', (done) => { + it('should disable auto launch', function (done) { autoLaunch.disable() .then(() => { autoLaunch.isEnabled() @@ -108,7 +108,7 @@ if (!isMac) { .catch(done); }); - it('should catch errors', (done) => { + it('should catch errors', function (done) { autoLaunchHelper.mockApi({ disable() { return Promise.reject(); @@ -121,7 +121,7 @@ if (!isMac) { /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ describe('.appName', () => { - it('should honor name parameter', (done) => { + it('should honor name parameter', function (done) { expect(autoLaunch.api.appName).to.equal('node-auto-launch test'); done(); }); @@ -149,7 +149,7 @@ if (isPosix) { }); describe('testing path name', () => { - it('should properly escape reserved caracters', (done) => { + it('should properly escape reserved caracters', function (done) { expect(autoLaunchPosix.api.appPath).to.equal(executablePathPosix.replace(/(\s+)/g, '\\$1')); done(); }); @@ -182,7 +182,7 @@ if (isMac) { autoLaunchWithLaunchAgentHelper.ensureDisabled(); }); - it('should be disabled', (done) => { + it('should be disabled', function (done) { autoLaunchWithLaunchAgent.isEnabled() .then((enabled) => { expect(enabled).to.equal(false); @@ -191,7 +191,7 @@ if (isMac) { .catch(done); }); - it('should catch errors', (done) => { + it('should catch errors', function (done) { autoLaunchWithLaunchAgentHelper.mockApi({ isEnabled() { return Promise.reject(); @@ -206,7 +206,7 @@ if (isMac) { autoLaunchWithLaunchAgentHelper.ensureDisabled(); }); - it('should enable auto launch', (done) => { + it('should enable auto launch', function (done) { autoLaunchWithLaunchAgent.enable() .then(() => { autoLaunchWithLaunchAgent.isEnabled() @@ -218,7 +218,7 @@ if (isMac) { .catch(done); }); - it('should catch errors', (done) => { + it('should catch errors', function (done) { autoLaunchWithLaunchAgentHelper.mockApi({ enable() { return Promise.reject(); @@ -234,7 +234,7 @@ if (isMac) { autoLaunchWithLaunchAgentHelper.ensureEnabled(); }); - it('should disable auto launch', (done) => { + it('should disable auto launch', function (done) { autoLaunchWithLaunchAgent.disable() .then(() => { autoLaunchWithLaunchAgent.isEnabled() @@ -246,7 +246,7 @@ if (isMac) { .catch(done); }); - it('should catch errors', (done) => { + it('should catch errors', function (done) { autoLaunchWithLaunchAgentHelper.mockApi({ disable() { return Promise.reject(); From 349d0487506791ff632ef342e93eff67fcc46077 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 1 Jan 2024 13:56:08 -0500 Subject: [PATCH 52/77] tests: hopefully fix the .enable() test false error under Linux Return a Promise where we have a better control on reject and resolve instead of using done(); Signed-off-by: Alexandre Demers --- tests/test.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/test.js b/tests/test.js index d65461a..3747b8c 100644 --- a/tests/test.js +++ b/tests/test.js @@ -64,20 +64,21 @@ if (!isMac) { autoLaunchHelper.ensureDisabled(); }); - it('should enable auto launch', (done) => { - autoLaunch.enable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - // done(); - }); - }) - // This should prevent done() from catching non-errors - .then(() => { - done(); - }) - .catch(done); + it('should enable auto launch', function () { + return new Promise((resolve, reject) => { + autoLaunch.enable() + .then(() => { + autoLaunch.isEnabled() + .then((enabled) => { + try { + expect(enabled).to.equal(true); + return resolve(enabled); + } catch (error) { + return reject(enabled); + } + }); + }); + }); }); it('should catch errors', function (done) { From 82fbeca694c8dd0e89b5fd5ea5999bf490df5ac0 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 1 Jan 2024 13:57:46 -0500 Subject: [PATCH 53/77] tests: add test coverage for AutoLauch constructor Test if "name" is null; Test if "name" is empty. For both scenarios, we expect an error. Signed-off-by: Alexandre Demers --- tests/test.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/test.js b/tests/test.js index 3747b8c..fe41235 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,4 +1,4 @@ -import { expect } from 'chai'; +import { expect, should } from 'chai'; import path from 'path'; import AutoLaunch from '../src/index.js'; import AutoLaunchHelper from './helper.js'; @@ -34,6 +34,30 @@ if (!isMac) { return autoLaunchHelper; }); + describe('AutoLaunch constructor', () => { + it('should fail without a name', function (done) { + try { + autoLaunch = new AutoLaunch({name: null}); + // Force the test to fail since error wasn't thrown + should.fail('It should have failed...'); + } catch (error) { + // Constructor threw Error, so test succeeded. + done(); + } + }); + + it('should fail with an empty name', function (done) { + try { + autoLaunch = new AutoLaunch({name: ''}); + // Force the test to fail since error wasn't thrown + should.fail('It should have failed...'); + } catch (error) { + // Constructor threw Error, so test succeeded. + done(); + } + }); + }); + describe('.isEnabled', () => { beforeEach(() => { autoLaunchHelper.ensureDisabled(); From 20cd60d60fd2893024867247590651000cce5383 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 1 Jan 2024 14:14:15 -0500 Subject: [PATCH 54/77] tests: add logs and a useless return that should never be called CI pass under macOS and Windows, but it still fails under Linux (but OK locally). Signed-off-by: Alexandre Demers --- tests/test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test.js b/tests/test.js index fe41235..c86152b 100644 --- a/tests/test.js +++ b/tests/test.js @@ -96,10 +96,13 @@ if (!isMac) { .then((enabled) => { try { expect(enabled).to.equal(true); + console.error('isEnabled() returned true.'); return resolve(enabled); } catch (error) { + console.error('isEnabled() returned false.'); return reject(enabled); } + return resolve(enabled); }); }); }); From af0b43c0e8c79265d9b2f1f7d1987d0888e8c032 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 01:59:20 -0500 Subject: [PATCH 55/77] Workflow: update to Actions v3 since Node 12 (v2) is now deprecated. This will shutoff some warnings. Signed-off-by: Alexandre Demers --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2efd44a..01d68d6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,10 +11,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} From 8891cd5c2b47a6b2d7baa613046ddbbdda0581c3 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 02:32:45 -0500 Subject: [PATCH 56/77] tests: another attemp at fixing .enable under CI - Linux It still works fine when tested locally, but how will the CI deal will it? Signed-off-by: Alexandre Demers --- tests/test.js | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/tests/test.js b/tests/test.js index c86152b..0bd92e7 100644 --- a/tests/test.js +++ b/tests/test.js @@ -88,24 +88,22 @@ if (!isMac) { autoLaunchHelper.ensureDisabled(); }); - it('should enable auto launch', function () { - return new Promise((resolve, reject) => { - autoLaunch.enable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - try { - expect(enabled).to.equal(true); - console.error('isEnabled() returned true.'); - return resolve(enabled); - } catch (error) { - console.error('isEnabled() returned false.'); - return reject(enabled); - } - return resolve(enabled); - }); - }); - }); + it('should enable auto launch', function (done) { + autoLaunch.enable() + .then(() => { + autoLaunch.isEnabled() + .then((enabled) => { + try { + expect(enabled).to.equal(true); + return null; + } catch (error) { + return error; + } + }) + .then((error) => { + done(error); + }); + }); }); it('should catch errors', function (done) { From a71ce01a643fc13cb1191419b2ae6e99d08890df Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 02:34:53 -0500 Subject: [PATCH 57/77] tests: could this be only because of a timeout? Signed-off-by: Alexandre Demers --- tests/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test.js b/tests/test.js index 0bd92e7..f4204db 100644 --- a/tests/test.js +++ b/tests/test.js @@ -89,6 +89,7 @@ if (!isMac) { }); it('should enable auto launch', function (done) { + this.timeout(5000); autoLaunch.enable() .then(() => { autoLaunch.isEnabled() From d2e794dc8f527f4e56e87761abe16bd443fe1fd6 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 02:37:09 -0500 Subject: [PATCH 58/77] tests: let's call done directly (which risk to cath non-error as before) Signed-off-by: Alexandre Demers --- tests/test.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test.js b/tests/test.js index f4204db..0e9318f 100644 --- a/tests/test.js +++ b/tests/test.js @@ -89,20 +89,16 @@ if (!isMac) { }); it('should enable auto launch', function (done) { - this.timeout(5000); autoLaunch.enable() .then(() => { autoLaunch.isEnabled() .then((enabled) => { try { - expect(enabled).to.equal(true); - return null; + expect(enabled).to.equal(false); + done(); } catch (error) { - return error; + done(error); } - }) - .then((error) => { - done(error); }); }); }); From 651bab5148c16b562b638fd3d578f2d08da2f032 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 02:39:36 -0500 Subject: [PATCH 59/77] tests: oups, forgot to put back the good expectation while testing locally Signed-off-by: Alexandre Demers --- tests/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.js b/tests/test.js index 0e9318f..7ab1b07 100644 --- a/tests/test.js +++ b/tests/test.js @@ -94,7 +94,7 @@ if (!isMac) { autoLaunch.isEnabled() .then((enabled) => { try { - expect(enabled).to.equal(false); + expect(enabled).to.equal(true); done(); } catch (error) { done(error); From 2cc044d1345eb06dcb4bcf1e1efb4df0729bf1dc Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 03:35:39 -0500 Subject: [PATCH 60/77] tests: another alternative Signed-off-by: Alexandre Demers --- tests/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test.js b/tests/test.js index 7ab1b07..5b8317a 100644 --- a/tests/test.js +++ b/tests/test.js @@ -95,10 +95,10 @@ if (!isMac) { .then((enabled) => { try { expect(enabled).to.equal(true); - done(); } catch (error) { - done(error); + return done(error); } + return done(); }); }); }); From 60fa131184e35b09b6b124e1cb47f85466d1131f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 03:46:20 -0500 Subject: [PATCH 61/77] tests: unify general and macOS ones If we need to test some specific macOS features, we will add specific tests. However, for now, we were testing the same thing, but with some options specific to macOS pushed to AutoLaunch's constructor. Signed-off-by: Alexandre Demers --- tests/test.js | 307 +++++++++++++++++--------------------------------- 1 file changed, 104 insertions(+), 203 deletions(-) diff --git a/tests/test.js b/tests/test.js index 5b8317a..4837595 100644 --- a/tests/test.js +++ b/tests/test.js @@ -20,137 +20,140 @@ if (/^win/.test(process.platform)) { console.log('Executable being used for tests:', executablePath); // General tests for all platforms -if (!isMac) { - describe('node-auto-launch', () => { - let autoLaunch = null; - let autoLaunchHelper = null; +describe('node-auto-launch', () => { + let autoLaunch = null; + let autoLaunchHelper = null; + + beforeEach(() => { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath, + options: { + mac: isMac ? { useLaunchAgent: true } : {} + } + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + return autoLaunchHelper; + }); + + describe('AutoLaunch constructor', () => { + it('should fail without a name', function (done) { + try { + autoLaunch = new AutoLaunch({name: null}); + // Force the test to fail since error wasn't thrown + should.fail('It should have failed...'); + } catch (error) { + // Constructor threw Error, so test succeeded. + done(); + } + }); + it('should fail with an empty name', function (done) { + try { + autoLaunch = new AutoLaunch({name: ''}); + // Force the test to fail since error wasn't thrown + should.fail('It should have failed...'); + } catch (error) { + // Constructor threw Error, so test succeeded. + done(); + } + }); + }); + + describe('.isEnabled', () => { beforeEach(() => { - autoLaunch = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePath - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - return autoLaunchHelper; + autoLaunchHelper.ensureDisabled(); }); - describe('AutoLaunch constructor', () => { - it('should fail without a name', function (done) { - try { - autoLaunch = new AutoLaunch({name: null}); - // Force the test to fail since error wasn't thrown - should.fail('It should have failed...'); - } catch (error) { - // Constructor threw Error, so test succeeded. + it('should be disabled', function (done) { + autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); done(); - } - }); + }) + .catch(done); + }); - it('should fail with an empty name', function (done) { - try { - autoLaunch = new AutoLaunch({name: ''}); - // Force the test to fail since error wasn't thrown - should.fail('It should have failed...'); - } catch (error) { - // Constructor threw Error, so test succeeded. - done(); + it('should catch errors', function (done) { + autoLaunchHelper.mockApi({ + isEnabled() { + return Promise.reject(); } }); - }); - describe('.isEnabled', () => { - beforeEach(() => { - autoLaunchHelper.ensureDisabled(); - }); + autoLaunch.isEnabled().catch(done); + }); + }); - it('should be disabled', function (done) { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(false); - done(); - }) - .catch(done); - }); + describe('.enable', () => { + beforeEach(() => { + autoLaunchHelper.ensureDisabled(); + }); - it('should catch errors', function (done) { - autoLaunchHelper.mockApi({ - isEnabled() { - return Promise.reject(); - } + it('should enable auto launch', function (done) { + autoLaunch.enable() + .then(() => { + autoLaunch.isEnabled() + .then((enabled) => { + try { + expect(enabled).to.equal(true); + } catch (error) { + return done(error); + } + return done(); + }); }); - - autoLaunch.isEnabled().catch(done); - }); }); - describe('.enable', () => { - beforeEach(() => { - autoLaunchHelper.ensureDisabled(); - }); - - it('should enable auto launch', function (done) { - autoLaunch.enable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - try { - expect(enabled).to.equal(true); - } catch (error) { - return done(error); - } - return done(); - }); - }); + it('should catch errors', function (done) { + autoLaunchHelper.mockApi({ + enable() { + return Promise.reject(); + } }); - it('should catch errors', function (done) { - autoLaunchHelper.mockApi({ - enable() { - return Promise.reject(); - } - }); + autoLaunch.enable().catch(done); + }); + }); - autoLaunch.enable().catch(done); - }); + describe('.disable', () => { + beforeEach(() => { + autoLaunchHelper.ensureEnabled(); }); - describe('.disable', () => { - beforeEach(() => { - autoLaunchHelper.ensureEnabled(); - }); + it('should disable auto launch', function (done) { + autoLaunch.disable() + .then(() => { + autoLaunch.isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); + done(); + }); + }) + .catch(done); + }); - it('should disable auto launch', function (done) { - autoLaunch.disable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(false); - done(); - }); - }) - .catch(done); + it('should catch errors', function (done) { + autoLaunchHelper.mockApi({ + disable() { + return Promise.reject(); + } }); - it('should catch errors', function (done) { - autoLaunchHelper.mockApi({ - disable() { - return Promise.reject(); - } - }); - - autoLaunch.disable().catch(done); - }); + autoLaunch.disable().catch(done); }); + }); - /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ + /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ + if (!isMac) { describe('.appName', () => { it('should honor name parameter', function (done) { expect(autoLaunch.api.appName).to.equal('node-auto-launch test'); done(); }); }); - }); -} + } +}); // Let's test some POSIX/Linux/FreeBSD options // They rely on reading and write files on POSIX based filesystems @@ -179,105 +182,3 @@ if (isPosix) { }); }); } - -// Let's test some Mac-only options -if (isMac) { - describe('mac.useLaunchAgent', () => { - let autoLaunchWithLaunchAgent = null; - let autoLaunchWithLaunchAgentHelper = null; - - beforeEach(() => { - autoLaunchWithLaunchAgent = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePath, - options: { - mac: { - useLaunchAgent: true - } - } - }); - autoLaunchWithLaunchAgentHelper = new AutoLaunchHelper(autoLaunchWithLaunchAgent); - return autoLaunchWithLaunchAgentHelper; - }); - - describe('.isEnabled', () => { - beforeEach(() => { - autoLaunchWithLaunchAgentHelper.ensureDisabled(); - }); - - it('should be disabled', function (done) { - autoLaunchWithLaunchAgent.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(false); - done(); - }) - .catch(done); - }); - - it('should catch errors', function (done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - isEnabled() { - return Promise.reject(); - } - }); - autoLaunchWithLaunchAgent.isEnabled().catch(done); - }); - }); - - describe('.enable', () => { - beforeEach(() => { - autoLaunchWithLaunchAgentHelper.ensureDisabled(); - }); - - it('should enable auto launch', function (done) { - autoLaunchWithLaunchAgent.enable() - .then(() => { - autoLaunchWithLaunchAgent.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - done(); - }); - }) - .catch(done); - }); - - it('should catch errors', function (done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - enable() { - return Promise.reject(); - } - }); - - autoLaunchWithLaunchAgent.enable().catch(done); - }); - }); - - describe('.disable', () => { - beforeEach(() => { - autoLaunchWithLaunchAgentHelper.ensureEnabled(); - }); - - it('should disable auto launch', function (done) { - autoLaunchWithLaunchAgent.disable() - .then(() => { - autoLaunchWithLaunchAgent.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(false); - done(); - }); - }) - .catch(done); - }); - - it('should catch errors', function (done) { - autoLaunchWithLaunchAgentHelper.mockApi({ - disable() { - return Promise.reject(); - } - }); - - autoLaunchWithLaunchAgent.disable().catch(done); - }); - }); - }); -} From aecd97331febcd03af774897f289c25ae2b71edd Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 03:55:22 -0500 Subject: [PATCH 62/77] tests: .enable() CI on Linux, another variant Still working on local Linux machine. Will it work in CI? Signed-off-by: Alexandre Demers --- tests/test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test.js b/tests/test.js index 4837595..4747863 100644 --- a/tests/test.js +++ b/tests/test.js @@ -98,9 +98,12 @@ describe('node-auto-launch', () => { try { expect(enabled).to.equal(true); } catch (error) { - return done(error); + return error; } - return done(); + return null; + }) + .then((checked) => { + done(checked); }); }); }); From e45716c8c89d4581a6276d4360acde307992937c Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 04:01:42 -0500 Subject: [PATCH 63/77] tests: CI Linux - with a catch(done)? Signed-off-by: Alexandre Demers --- tests/test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test.js b/tests/test.js index 4747863..74380cb 100644 --- a/tests/test.js +++ b/tests/test.js @@ -102,10 +102,11 @@ describe('node-auto-launch', () => { } return null; }) - .then((checked) => { - done(checked); + .then((error) => { + done(error); }); - }); + }) + .catch(done); }); it('should catch errors', function (done) { From 2e2a6ccea482428a59dc1b18405556556b502aad Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 04:05:01 -0500 Subject: [PATCH 64/77] tests: add a log to help us Because we are back at the start where done() catches a non-error pointing at ~/.config/autostart Signed-off-by: Alexandre Demers --- tests/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test.js b/tests/test.js index 74380cb..87652ad 100644 --- a/tests/test.js +++ b/tests/test.js @@ -98,6 +98,7 @@ describe('node-auto-launch', () => { try { expect(enabled).to.equal(true); } catch (error) { + console.log('Oops, .isEnabled() failed? ', error); return error; } return null; From 75411a779e6c41ced6ae1e31fd7c523b3aede55b Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 04:11:07 -0500 Subject: [PATCH 65/77] tests: let's see if error is an instance of Error class Maybe this will do the trick. Signed-off-by: Alexandre Demers --- tests/test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test.js b/tests/test.js index 87652ad..ba49ea9 100644 --- a/tests/test.js +++ b/tests/test.js @@ -98,13 +98,16 @@ describe('node-auto-launch', () => { try { expect(enabled).to.equal(true); } catch (error) { - console.log('Oops, .isEnabled() failed? ', error); return error; } return null; }) .then((error) => { - done(error); + if (error instanceof Error) { + done(error); + } else { + done(); + } }); }) .catch(done); From 4aadd9e9bb29a6a216a2df630ec723934b7750c9 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Tue, 2 Jan 2024 15:02:48 -0500 Subject: [PATCH 66/77] tests: fix for real CI on Linux by fix createFile() + fix catch(done) The problem was not at all where I was looking for it. The error was arising on CI because the autostart folder must not exists. Thus, createFile() was wrongly throwing an error after calling mkdirp. Mkdirp returns a string if a folder is created (the first one created if recursive) or undefined if the folder already exists. In case of error, it rejects the Promise. Since Node fs can manage mkdir recursively itself, let's use the native call and use the callback to manage the error/rejection if any. Fix catch(done) to catch failures properly. Signed-off-by: Alexandre Demers --- src/library/fileBasedUtilities.js | 20 +++++++++----------- tests/test.js | 29 +++++++++-------------------- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/library/fileBasedUtilities.js b/src/library/fileBasedUtilities.js index 9c7b276..3bc76a3 100644 --- a/src/library/fileBasedUtilities.js +++ b/src/library/fileBasedUtilities.js @@ -1,5 +1,4 @@ import fs from 'fs'; -import { mkdirp } from 'mkdirp'; // Public: a few utils for file-based auto-launching @@ -11,18 +10,17 @@ import { mkdirp } from 'mkdirp'; // Returns a Promise export function createFile({directory, filePath, data}) { return new Promise((resolve, reject) => { - mkdirp(directory) - .then((mkdirErr) => { - if (mkdirErr != null) { - return reject(mkdirErr); + fs.mkdir(directory, { recursive: true }, (mkdirErr, path) => { + if (mkdirErr != null) { + return reject(mkdirErr); + } + return fs.writeFile(filePath, data, (writeErr) => { + if (writeErr != null) { + return reject(writeErr); } - return fs.writeFile(filePath, data, (writeErr) => { - if (writeErr != null) { - return reject(writeErr); - } - return resolve(); - }); + return resolve(); }); + }); }); } diff --git a/tests/test.js b/tests/test.js index ba49ea9..e7d015b 100644 --- a/tests/test.js +++ b/tests/test.js @@ -39,7 +39,7 @@ describe('node-auto-launch', () => { describe('AutoLaunch constructor', () => { it('should fail without a name', function (done) { try { - autoLaunch = new AutoLaunch({name: null}); + autoLaunch = new AutoLaunch({ name: null }); // Force the test to fail since error wasn't thrown should.fail('It should have failed...'); } catch (error) { @@ -50,7 +50,7 @@ describe('node-auto-launch', () => { it('should fail with an empty name', function (done) { try { - autoLaunch = new AutoLaunch({name: ''}); + autoLaunch = new AutoLaunch({ name: '' }); // Force the test to fail since error wasn't thrown should.fail('It should have failed...'); } catch (error) { @@ -95,22 +95,11 @@ describe('node-auto-launch', () => { .then(() => { autoLaunch.isEnabled() .then((enabled) => { - try { - expect(enabled).to.equal(true); - } catch (error) { - return error; - } - return null; + expect(enabled).to.equal(true); + done(); }) - .then((error) => { - if (error instanceof Error) { - done(error); - } else { - done(); - } - }); - }) - .catch(done); + .catch(done); + }); }); it('should catch errors', function (done) { @@ -136,9 +125,9 @@ describe('node-auto-launch', () => { .then((enabled) => { expect(enabled).to.equal(false); done(); - }); - }) - .catch(done); + }) + .catch(done); + }); }); it('should catch errors', function (done) { From 228708eaa71a0c50df59426ad0527436e8ed25c7 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 22 Jan 2024 20:11:26 -0500 Subject: [PATCH 67/77] mockApi: remove unneeded return Signed-off-by: Alexandre Demers --- tests/helper.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/helper.js b/tests/helper.js index a19f588..eded865 100644 --- a/tests/helper.js +++ b/tests/helper.js @@ -21,8 +21,7 @@ export default class AutoLaunchHelper { }); } - mockApi(stubs) { - this.autoLaunch.api = stubs; - return this.autoLaunch.api; + mockApi(stub) { + this.autoLaunch.api = stub; } } From 61747783ba088d6889fefe068a5c25df6857f72a Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 22 Jan 2024 20:15:35 -0500 Subject: [PATCH 68/77] tests: rework some tests so we properly clean behind us and add POSIX tests We were leaving garbages behind us when testing. Make sure we clean it up. To allow proper cleanup, move the failure tests all together so they don't mix up with the after/afterEach call. POSIX: add some tests to ensure we properly honor appName with the Desktop entry file. --- tests/test.js | 175 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 138 insertions(+), 37 deletions(-) diff --git a/tests/test.js b/tests/test.js index e7d015b..7c6f269 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,10 +1,13 @@ import { expect, should } from 'chai'; +import fs from 'fs'; import path from 'path'; +import untildify from 'untildify'; import AutoLaunch from '../src/index.js'; import AutoLaunchHelper from './helper.js'; let executablePath = ''; -let isPosix = false; +let followsXDG = false; +let isPOSIX = false; let isMac = false; if (/^win/.test(process.platform)) { @@ -13,7 +16,8 @@ if (/^win/.test(process.platform)) { isMac = true; executablePath = '/Applications/Calculator.app'; } else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - isPosix = true; + followsXDG = true; + isPOSIX = true; executablePath = path.resolve(path.join('./tests/executables', 'hv3-linux-x86')); } @@ -33,7 +37,6 @@ describe('node-auto-launch', () => { } }); autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - return autoLaunchHelper; }); describe('AutoLaunch constructor', () => { @@ -61,7 +64,7 @@ describe('node-auto-launch', () => { }); describe('.isEnabled', () => { - beforeEach(() => { + before(() => { autoLaunchHelper.ensureDisabled(); }); @@ -74,19 +77,13 @@ describe('node-auto-launch', () => { .catch(done); }); - it('should catch errors', function (done) { - autoLaunchHelper.mockApi({ - isEnabled() { - return Promise.reject(); - } - }); - - autoLaunch.isEnabled().catch(done); + after(() => { + autoLaunchHelper.ensureDisabled(); }); }); describe('.enable', () => { - beforeEach(() => { + before(() => { autoLaunchHelper.ensureDisabled(); }); @@ -102,14 +99,8 @@ describe('node-auto-launch', () => { }); }); - it('should catch errors', function (done) { - autoLaunchHelper.mockApi({ - enable() { - return Promise.reject(); - } - }); - - autoLaunch.enable().catch(done); + after(() => { + autoLaunchHelper.ensureDisabled(); }); }); @@ -130,13 +121,39 @@ describe('node-auto-launch', () => { }); }); - it('should catch errors', function (done) { + afterEach(() => { + autoLaunchHelper.ensureDisabled(); + }); + }); + + describe('Let\'s catch errors', () => { + it('should catch isEnable() errors', function (done) { autoLaunchHelper.mockApi({ - disable() { + isEnabled() { return Promise.reject(); } }); + autoLaunch.isEnabled().catch(done); + }); + + it('should catch enable() errors', function (done) { + autoLaunchHelper.mockApi({ + enable() { + return Promise.reject(); + } + }); + autoLaunch.enable().catch(done); + }); + + it('should catch disable() errors', function (done) { + autoLaunchHelper.ensureEnabled(); + + autoLaunchHelper.mockApi({ + disable() { + return Promise.reject(); + } + }); autoLaunch.disable().catch(done); }); }); @@ -153,29 +170,113 @@ describe('node-auto-launch', () => { }); // Let's test some POSIX/Linux/FreeBSD options -// They rely on reading and write files on POSIX based filesystems -if (isPosix) { +// They rely on reading and write files on POSIX based filesystems and +if (isPOSIX) { describe('POSIX/Linux/FreeBSD tests', () => { - let autoLaunchPosix = null; - // let autoLaunchPosixHelper = null; + let autoLaunch = null; + let autoLaunchHelper = null; const executablePathPosix = path.resolve('./path with spaces/'); - beforeEach(() => { - autoLaunchPosix = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePathPosix, - options: { - mac: isMac ? { useLaunchAgent: true } : {} - } + // OSes/window managers that follow XDG (cross desktop group) specifications + if (followsXDG) { + describe('testing .appName', () => { + beforeEach(() => { + autoLaunch = null; + autoLaunchHelper = null; + }); + + it('without space', function (done) { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch', + path: executablePathPosix + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper.ensureDisabled(); + + autoLaunch.enable() + .then(() => { + const desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunch.api.appName + '.desktop')); + fs.stat(desktopEntryPath, (err, stats) => { + if (err) { + done(err); + } + expect(stats.isFile()).to.equal(true); + done(); + }); + }) + .catch(done); + }); + + it('with space', function (done) { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePathPosix + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper.ensureDisabled(); + + autoLaunch.enable() + .then(() => { + const desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunch.api.appName + '.desktop')); + fs.stat(desktopEntryPath, (err, stats) => { + if (err) { + done(err); + } + expect(stats.isFile()).to.equal(true); + done(); + }); + }) + .catch(done); + }); + + it('with capital letters', function (done) { + autoLaunch = new AutoLaunch({ + name: 'Node-Auto-Launch', + path: executablePathPosix + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper.ensureDisabled(); + + autoLaunch.enable() + .then(() => { + const desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunch.api.appName + '.desktop')); + fs.stat(desktopEntryPath, (err, stats) => { + if (err) { + done(err); + } + expect(stats.isFile()).to.equal(true); + done(); + }); + }) + .catch(done); + }); + + afterEach(() => { + autoLaunchHelper.ensureDisabled(); + }); }); - // autoLaunchPosixHelper = new AutoLaunchHelper(autoLaunchPosix); - }); + } describe('testing path name', () => { + beforeEach(() => { + autoLaunch = null; + autoLaunchHelper = null; + }); + it('should properly escape reserved caracters', function (done) { - expect(autoLaunchPosix.api.appPath).to.equal(executablePathPosix.replace(/(\s+)/g, '\\$1')); + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePathPosix + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + + expect(autoLaunch.api.appPath).to.equal(executablePathPosix.replace(/(\s+)/g, '\\$1')); done(); }); + + afterEach(() => { + autoLaunchHelper.ensureDisabled(); + }); }); }); } From 163593e0e77f63ed5f24f2dd34eda90869000f44 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Mon, 26 Feb 2024 00:51:46 -0500 Subject: [PATCH 69/77] 5.1.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 583612f..a2d5e2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "5.0.6", + "version": "5.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0cfb748..45b64d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "5.0.6", + "version": "5.1.0", "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "type": "module", "main": "./src/index.js", From 4e64b1ba2faf20972dc55465f1c88182f6d00215 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Thu, 7 Mar 2024 01:56:16 -0500 Subject: [PATCH 70/77] Remove mkdirp from dependencies Signed-off-by: Alexandre Demers --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 0cfb748..ded6c9f 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,6 @@ }, "dependencies": { "applescript": "^1.0.0", - "mkdirp": "^3.0.0", "untildify": "^5.0.0", "winreg": "1.2.4" } From 264b7b2bfab43e27a6c47924c6ebc90db3b2919f Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 22 Mar 2024 01:43:49 -0400 Subject: [PATCH 71/77] Windows: improve tracking path used to launch app and error messages To help solve issue 122, improve the information logged about the app's path and any error message when registring or unregistring the registry key. (see https://github.com/Teamwork/node-auto-launch/issues/122) Signed-off-by: Alexandre Demers --- src/library/autoLaunchAPI/autoLaunchAPIWindows.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/library/autoLaunchAPI/autoLaunchAPIWindows.js b/src/library/autoLaunchAPI/autoLaunchAPIWindows.js index 97cfd01..082657c 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIWindows.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIWindows.js @@ -18,16 +18,17 @@ export default class AutoLaunchAPIWindows extends AutoLaunchAPI { // Returns a Promise enable() { return new Promise((resolve, reject) => { - // 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 let args = ''; let pathToAutoLaunchedApp; const hiddenArg = this.options.launchInBackground; const extraArgs = this.options.extraArguments; const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe'); + // 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 if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) { pathToAutoLaunchedApp = `"${updateDotExe}"`; + console.log('This application is built on Electron and is launched through: ', pathToAutoLaunchedApp); args = ` --processStart "${path.basename(process.execPath)}"`; // Manage arguments @@ -47,14 +48,18 @@ export default class AutoLaunchAPIWindows extends AutoLaunchAPI { // 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 != null) { + if (process.windowsStore) { pathToAutoLaunchedApp = `"explorer.exe" shell:AppsFolder\\${this.appPath}`; + console.log('This application is an AppX and is launched through: ', pathToAutoLaunchedApp); } else { pathToAutoLaunchedApp = `"${this.appPath}"`; + console.log('This application is launched through: ', pathToAutoLaunchedApp); } // Manage arguments - if (hiddenArg) { args = [(hiddenArg !== true) ? hiddenArg : ' --hidden']; } + if (hiddenArg) { + args = [(hiddenArg !== true) ? hiddenArg : ' --hidden']; + } // Add any extra arguments if (extraArgs) { args += ' '; @@ -64,6 +69,7 @@ export default class AutoLaunchAPIWindows extends AutoLaunchAPI { regKey.set(this.appName, Winreg.REG_SZ, `"${pathToAutoLaunchedApp}"${args}`, (err) => { if (err != null) { + console.log(err.message); return reject(err); } return resolve(); @@ -94,6 +100,7 @@ export default class AutoLaunchAPIWindows extends AutoLaunchAPI { return new Promise((resolve, reject) => { regKey.valueExists(this.appName, (err, exists) => { if (err != null) { + console.log(err.message); return resolve(false); } return resolve(exists); From fe027c31ce80534cfaf6e8080f1812220391e9ae Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 22 Mar 2024 01:45:13 -0400 Subject: [PATCH 72/77] Update comments for better understanding of the code Signed-off-by: Alexandre Demers --- src/index.js | 8 ++++++-- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 15 +++++++-------- tests/test.js | 1 + 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/index.js b/src/index.js index 2035e4d..bf89728 100644 --- a/src/index.js +++ b/src/index.js @@ -29,11 +29,15 @@ export default class AutoLaunch { const versions = typeof process !== 'undefined' && process !== null ? process.versions : undefined; if (path != null) { - // Verify that the path is absolute - if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { throw new Error('path must be absolute'); } + // Verify that the path is absolute or is an AppX path + if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { + throw new Error('path must be absolute'); + } opts.appPath = path; } else if ((versions != null) && ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) { + // Autodetecting the appPath from the execPath. // This appPath will need to be fixed later depending of the OS used + // TODO: is this the reason behind issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 opts.appPath = process.execPath; } else { throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index a013d46..1c9b2db 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -138,18 +138,17 @@ export default class AutoLaunchAPIMac extends AutoLaunchAPI { return execPath; } + // Kept from Coffeescript, but should we honor the name given to autoLaunch or should we change it specifically for macOS? + // No explanation, see issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 #fixAppName() { let fixedName; - // Kept from Coffeescript, but should we honor the name given to autoLaunch or should we change it for macOS? - if (/darwin/.test(process.platform)) { - const tempPath = this.appPath.split('/'); + const tempPath = this.appPath.split('/'); - fixedName = tempPath[tempPath.length - 1]; - // Remove ".app" from the appName if it exists - if (fixedName.indexOf('.app', fixedName.length - '.app'.length) !== -1) { - fixedName = fixedName.substr(0, fixedName.length - '.app'.length); - } + fixedName = tempPath[tempPath.length - 1]; + // Remove ".app" from the appName if it exists + if (fixedName.indexOf('.app', fixedName.length - '.app'.length) !== -1) { + fixedName = fixedName.substr(0, fixedName.length - '.app'.length); } return fixedName; diff --git a/tests/test.js b/tests/test.js index 7c6f269..e83af15 100644 --- a/tests/test.js +++ b/tests/test.js @@ -159,6 +159,7 @@ describe('node-auto-launch', () => { }); /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ + // See issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 if (!isMac) { describe('.appName', () => { it('should honor name parameter', function (done) { From 7d426cfed5996436ca9891235066d05f44844a8b Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 22 Mar 2024 02:17:39 -0400 Subject: [PATCH 73/77] 5.1.1-rc.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2d5e2f..a2434e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "5.1.0", + "version": "5.1.1-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5be3224..77fb7d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "5.1.0", + "version": "5.1.1-rc.0", "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "type": "module", "main": "./src/index.js", From fed35dc25f0b549f7f6d5f345ae5aca076520d3e Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 22 Mar 2024 02:18:17 -0400 Subject: [PATCH 74/77] 6.0.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2434e3..7cd4a16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "5.1.1-rc.0", + "version": "6.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 77fb7d3..3d845ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "5.1.1-rc.0", + "version": "6.0.0", "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "type": "module", "main": "./src/index.js", From ca7b02ebd64eb76c051a8c40794b6a85f0797c6d Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 22 Mar 2024 02:18:24 -0400 Subject: [PATCH 75/77] 6.0.1-rc.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7cd4a16..bb05be6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "6.0.0", + "version": "6.0.1-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3d845ea..3c5ce58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "6.0.0", + "version": "6.0.1-rc.0", "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "type": "module", "main": "./src/index.js", From 547c9da43c3d18175419c95bff26fb19f85b0f88 Mon Sep 17 00:00:00 2001 From: Alexandre Demers Date: Fri, 22 Mar 2024 02:20:44 -0400 Subject: [PATCH 76/77] Bump version to 6.0.0 and actually prepare release candidate Actually bump major version for RC preparation Signed-off-by: Alexandre Demers --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb05be6..fcc5c96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "6.0.1-rc.0", + "version": "6.0.0-rc.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3c5ce58..3e738dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "auto-launch", - "version": "6.0.1-rc.0", + "version": "6.0.0-rc.2", "description": "Launch node applications or executables at login (Mac, Windows, and Linux)", "type": "module", "main": "./src/index.js", From 5b21022862e8baabb88bea0912da9652973fd69d Mon Sep 17 00:00:00 2001 From: Donal Linehan Date: Tue, 9 Apr 2024 12:31:17 +0100 Subject: [PATCH 77/77] Reformat and lint fix --- .babelrc | 2 +- .editorconfig | 13 +- .eslintrc.json | 73 +- package-lock.json | 5761 +++++++++++++++-- package.json | 2 +- src/index.js | 106 +- src/library/autoLaunchAPI/autoLaunchAPI.js | 54 +- .../autoLaunchAPI/autoLaunchAPILinux.js | 136 +- src/library/autoLaunchAPI/autoLaunchAPIMac.js | 229 +- .../autoLaunchAPI/autoLaunchAPIWindows.js | 180 +- src/library/autoLaunchHandler.js | 20 +- src/library/fileBasedUtilities.js | 70 +- tests/helper.js | 44 +- tests/test.js | 483 +- 14 files changed, 6008 insertions(+), 1165 deletions(-) diff --git a/.babelrc b/.babelrc index d3337dc..4cecb55 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,3 @@ { - "presets": [ "@babel/preset-env" ] + "presets": [ "@babel/preset-env" ] } diff --git a/.editorconfig b/.editorconfig index 8a2b8e1..8dc7206 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,18 +6,7 @@ root = true [*] charset = "utf-8" indent_style = space -indent_size = 4 +indent_size = 2 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true - -[{package.json,package-lock.json}] -indent_size = 2 - -[*.js] -indent_style = space -indent_size = 4 - -[*.json] -indent_style = space -indent_size = 4 diff --git a/.eslintrc.json b/.eslintrc.json index 76ec1e8..9d236df 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,29 +1,48 @@ { - "extends": "airbnb-base", - "env": { - "browser": true, - "mocha": true - }, - "parser": "@babel/eslint-parser", - "parserOptions": { - "requireConfigFile": false, - "sourceType": "module" - }, - "rules": { - "brace-style": "warn", - "class-methods-use-this": 0, - "comma-dangle": ["warn", "only-multiline"], - "indent": ["warn", 4, { "SwitchCase": 1 }], - "lines-between-class-members": "off", - "linebreak-style": "off", - "max-len": ["warn", 128], - "no-promise-executor-return": "warn", - "no-var": "error", - "no-useless-constructor": "off", - "object-curly-newline": "warn", - "object-curly-spacing": "warn", - "prefer-arrow-callback": "off", - "prefer-const": "warn", - "prefer-destructuring": "off" - } + "extends": "airbnb-base", + "env": { + "browser": true, + "mocha": true + }, + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false, + "sourceType": "module" + }, + "rules": { + "brace-style": "warn", + "class-methods-use-this": 0, + "comma-dangle": [ + "warn", + "only-multiline" + ], + "indent": [ + "warn", + 2, + { + "SwitchCase": 1 + } + ], + "lines-between-class-members": "off", + "linebreak-style": "off", + "max-len": [ + "warn", + 128 + ], + "no-promise-executor-return": "warn", + "no-var": "error", + "no-useless-constructor": "off", + "object-curly-newline": "warn", + "object-curly-spacing": "warn", + "prefer-arrow-callback": "off", + "prefer-const": "warn", + "prefer-destructuring": "off", + "import/extensions": [ + "error", + "ignorePackages", + { + "js": "always" + } + ] + } } diff --git a/package-lock.json b/package-lock.json index 2392fdd..6c34199 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,662 +1,5488 @@ { "name": "auto-launch", "version": "6.0.0-rc.2", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "auto-launch", - "version": "5.1.0", + "version": "6.0.0-rc.2", "license": "MIT", "dependencies": { "applescript": "^1.0.0", - "mkdirp": "^0.5.1", - "untildify": "^3.0.2", + "untildify": "^5.0.0", "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" + "@babel/core": "^7.23.6", + "@babel/eslint-parser": "^7.23.0", + "@babel/preset-env": "^7.23.6", + "chai": "^4.3.0", + "eslint": "^8.55.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.29.0", + "mocha": "^10.2.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.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==", + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "coffeescript": "2.7.0", - "glob": "^8.0.1", - "ignore": "^5.2.0", - "resolve": "^1.21.0", - "strip-json-comments": "^3.1.1", - "yargs": "^17.3.1" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, - "bin": { - "coffeelint": "bin/coffeelint" + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { - "node": ">=12.x" + "node": ">=6.9.0" } }, - "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==", + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, "engines": { - "node": ">= 4" + "node": ">=6.9.0" } }, - "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==", + "node_modules/@babel/core": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "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==", + "node_modules/@babel/eslint-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", + "integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" } }, - "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==", + "node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/applescript": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz", - "integrity": "sha1-u4evVoytA0pOSMS9r2Bno6JwExc=" + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/assertion-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", - "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, "engines": { - "node": "*" + "node": ">=6.9.0" } }, - "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 + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } }, - "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==", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "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 + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } }, - "node_modules/chai": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", - "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "assertion-error": "^1.0.1", - "deep-eql": "^0.1.3", - "type-detect": "^1.0.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { - "node": ">= 0.4.0" + "node": ">=6.9.0" } }, - "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==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/coffeescript": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz", - "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", "dev": true, - "bin": { - "cake": "bin/cake", - "coffee": "bin/coffee" + "dependencies": { + "@babel/types": "^7.23.0" }, "engines": { - "node": ">=6" + "node": ">=6.9.0" } }, - "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==", + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@babel/types": "^7.24.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" } }, - "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 + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } }, - "node_modules/commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dev": true, "dependencies": { - "graceful-readlink": ">= 1.0.0" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">= 0.6.x" + "node": ">=6.9.0" } }, - "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 + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "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==", + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/deep-eql": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "dev": true, "dependencies": { - "type-detect": "0.1.1" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "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=", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, "engines": { - "node": "*" + "node": ">=6.9.0" } }, - "node_modules/diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha512-597ykPFhtJYaXqPq6fF7Vl1fXTKgPdLOntyxpmdzUOKiYGqK7zcnbplj5088+8qJnWdzXhyeau5iVr8HVo9dgg==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, "engines": { - "node": ">=0.3.1" + "node": ">=6.9.0" } }, - "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 + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { - "node": ">=6" + "node": ">=6.9.0" } }, - "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==", + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=6.9.0" } }, - "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 + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } }, - "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==", + "node_modules/@babel/helpers": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "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==", + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=6.9.0" } }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", + "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", + "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.1", + "@babel/plugin-syntax-import-attributes": "^7.24.1", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.1", + "@babel/plugin-transform-async-generator-functions": "^7.24.3", + "@babel/plugin-transform-async-to-generator": "^7.24.1", + "@babel/plugin-transform-block-scoped-functions": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", + "@babel/plugin-transform-classes": "^7.24.1", + "@babel/plugin-transform-computed-properties": "^7.24.1", + "@babel/plugin-transform-destructuring": "^7.24.1", + "@babel/plugin-transform-dotall-regex": "^7.24.1", + "@babel/plugin-transform-duplicate-keys": "^7.24.1", + "@babel/plugin-transform-dynamic-import": "^7.24.1", + "@babel/plugin-transform-exponentiation-operator": "^7.24.1", + "@babel/plugin-transform-export-namespace-from": "^7.24.1", + "@babel/plugin-transform-for-of": "^7.24.1", + "@babel/plugin-transform-function-name": "^7.24.1", + "@babel/plugin-transform-json-strings": "^7.24.1", + "@babel/plugin-transform-literals": "^7.24.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.1", + "@babel/plugin-transform-member-expression-literals": "^7.24.1", + "@babel/plugin-transform-modules-amd": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-modules-systemjs": "^7.24.1", + "@babel/plugin-transform-modules-umd": "^7.24.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.24.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", + "@babel/plugin-transform-numeric-separator": "^7.24.1", + "@babel/plugin-transform-object-rest-spread": "^7.24.1", + "@babel/plugin-transform-object-super": "^7.24.1", + "@babel/plugin-transform-optional-catch-binding": "^7.24.1", + "@babel/plugin-transform-optional-chaining": "^7.24.1", + "@babel/plugin-transform-parameters": "^7.24.1", + "@babel/plugin-transform-private-methods": "^7.24.1", + "@babel/plugin-transform-private-property-in-object": "^7.24.1", + "@babel/plugin-transform-property-literals": "^7.24.1", + "@babel/plugin-transform-regenerator": "^7.24.1", + "@babel/plugin-transform-reserved-words": "^7.24.1", + "@babel/plugin-transform-shorthand-properties": "^7.24.1", + "@babel/plugin-transform-spread": "^7.24.1", + "@babel/plugin-transform-sticky-regex": "^7.24.1", + "@babel/plugin-transform-template-literals": "^7.24.1", + "@babel/plugin-transform-typeof-symbol": "^7.24.1", + "@babel/plugin-transform-unicode-escapes": "^7.24.1", + "@babel/plugin-transform-unicode-property-regex": "^7.24.1", + "@babel/plugin-transform-unicode-regex": "^7.24.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/applescript": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz", + "integrity": "sha1-u4evVoytA0pOSMS9r2Bno6JwExc=" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz", + "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "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 + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001607", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001607.tgz", + "integrity": "sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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 + }, + "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 + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.730", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.730.tgz", + "integrity": "sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==", + "dev": true + }, + "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 + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "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 + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "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" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "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, + "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": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mocha": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", + "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "8.1.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/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": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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 + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "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" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/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": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "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 - }, - "node_modules/growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha512-RTBwDHhNuOx4F0hqzItc/siXCasGfC4DeWcBamclWd+6jWtBaeB/SGbMkGf0eiQoW7ib8JpvOgnUsmgMHI3Mfw==", + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "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==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.2" + "is-number": "^7.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8.0" } }, - "node_modules/he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA==", + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "bin": { - "he": "bin/he" + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "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==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "prelude-ls": "^1.2.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.8.0" } }, - "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==", + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, - "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 - }, - "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==", + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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 - }, - "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 - }, - "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 - }, - "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 - }, - "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==", + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "dependencies": { - "lodash._baseassign": "^3.0.0", - "lodash._basecreate": "^3.0.0", - "lodash._isiterateecall": "^3.0.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" } }, - "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 - }, - "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 - }, - "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==", + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { - "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=" - }, - "node_modules/mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "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" - } - }, - "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, - "dependencies": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.6.8", - "diff": "3.2.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "he": "1.1.1", - "json3": "3.3.2", - "lodash.create": "3.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": ">= 0.10.x", - "npm": ">= 1.4.x" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "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" + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/ms": { + "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "dependencies": { - "wrappy": "1" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "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=", + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "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 - }, - "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==", + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/untildify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-5.0.0.tgz", + "integrity": "sha512-bOgQLUnd2G5rhzaTvh1VCI9Fo6bC5cLTpH17T5aFfamyXFYDbbdzN6IXdeoc3jBS7T9hNTmJtYUzJCJ2Xlc9gA==", + "engines": { + "node": ">=16" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "escalade": "^3.1.1", + "picocolors": "^1.0.0" }, "bin": { - "resolve": "bin/resolve" + "update-browserslist-db": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "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==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "punycode": "^2.1.0" } }, - "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==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "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==", + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "dependencies": { - "has-flag": "^1.0.0" + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" }, - "engines": { - "node": ">=0.8.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, "engines": { "node": ">= 0.4" }, @@ -664,34 +5490,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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 - }, - "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, - "engines": { - "node": "*" - } - }, - "node_modules/untildify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", - "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=", - "engines": { - "node": ">=4" - } - }, "node_modules/winreg": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz", "integrity": "sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=" }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -724,31 +5533,37 @@ "node": ">=10" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" }, "engines": { - "node": ">=12" + "node": ">=10" } }, - "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==", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { - "node": ">=12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/package.json b/package.json index fb038a5..1a99244 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "exports": "./src/index.js", "scripts": { "lint": "eslint --ext .js src tests", - "lint:fix": "pnpm lint --fix", + "lint:fix": "eslint --ext .js src tests --fix", "test": "mocha tests/test.js --reporter spec" }, "pre-commit": { diff --git a/src/index.js b/src/index.js index bf89728..2f27818 100644 --- a/src/index.js +++ b/src/index.js @@ -1,61 +1,63 @@ import pathTools from 'path'; -import autoLaunchHandler from './library/autoLaunchHandler.js' +import autoLaunchHandler from './library/autoLaunchHandler.js'; // Public: The main auto-launch class export default class AutoLaunch { - /* Public */ - - // {Object} - // :name - {String} - // :path - (Optional) {String} - // :options - (Optional) {Object} - // :launchInBackground, - (Optional) {String}. If set, either use default --hidden arg or specified one. - // :mac - (Optional) {Object} - // :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript - // to add Login Item - // :extraArgs - (Optional) {Array} - constructor({ name, path, options }) { - // Name is the only mandatory parameter and must neither be null nor empty - if (!name) { throw new Error('You must specify a name'); } - - let opts = { - appName: name, - options: { - launchInBackground: (options && (options.launchInBackground != null)) ? options.launchInBackground : false, - mac: (options && (options.mac != null)) ? options.mac : {}, - extraArguments: (options && (options.extraArguments != null)) ? options.extraArgs : [] - } - }; - - const versions = typeof process !== 'undefined' && process !== null ? process.versions : undefined; - if (path != null) { - // Verify that the path is absolute or is an AppX path - if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { - throw new Error('path must be absolute'); - } - opts.appPath = path; - } else if ((versions != null) && ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) { - // Autodetecting the appPath from the execPath. - // This appPath will need to be fixed later depending of the OS used - // TODO: is this the reason behind issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 - opts.appPath = process.execPath; - } else { - throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); - } - - this.api = autoLaunchHandler(opts); + /* Public */ + + // {Object} + // :name - {String} + // :path - (Optional) {String} + // :options - (Optional) {Object} + // :launchInBackground, - (Optional) {String}. If set, either use default --hidden arg or specified one. + // :mac - (Optional) {Object} + // :useLaunchAgent - (Optional) {Boolean}. If `true`, use filed-based Launch Agent. Otherwise use AppleScript + // to add Login Item + // :extraArgs - (Optional) {Array} + constructor({ name, path, options }) { + // Name is the only mandatory parameter and must neither be null nor empty + if (!name) { throw new Error('You must specify a name'); } + + const opts = { + appName: name, + options: { + launchInBackground: (options && (options.launchInBackground != null)) ? options.launchInBackground : false, + mac: (options && (options.mac != null)) ? options.mac : {}, + extraArguments: (options && (options.extraArguments != null)) ? options.extraArgs : [] + } + }; + + const versions = typeof process !== 'undefined' && process !== null ? process.versions : undefined; + if (path != null) { + // Verify that the path is absolute or is an AppX path + if ((!pathTools.isAbsolute(path)) && !process.windowsStore) { + throw new Error('path must be absolute'); + } + opts.appPath = path; + } else if ( + (versions != null) + && ((versions.nw != null) || (versions['node-webkit'] != null) || (versions.electron != null))) { + // Autodetecting the appPath from the execPath. + // This appPath will need to be fixed later depending of the OS used + // TODO: is this the reason behind issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 + opts.appPath = process.execPath; + } else { + throw new Error('You must give a path (this is only auto-detected for NW.js and Electron apps)'); } - enable() { - return this.api.enable(); - } + this.api = autoLaunchHandler(opts); + } - disable() { - return this.api.disable(); - } + enable() { + return this.api.enable(); + } - // Returns a Promise which resolves to a {Boolean} - isEnabled() { - return this.api.isEnabled(); - } + disable() { + return this.api.disable(); + } + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + return this.api.isEnabled(); + } } diff --git a/src/library/autoLaunchAPI/autoLaunchAPI.js b/src/library/autoLaunchAPI/autoLaunchAPI.js index 7f0c5a3..a8aedd7 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPI.js +++ b/src/library/autoLaunchAPI/autoLaunchAPI.js @@ -1,33 +1,33 @@ export default class AutoLaunchAPI { - /* Public */ + /* Public */ - // init - {Object} - // :appName - {String} - // :appPath - {String} - // :options - {Object} - // :launchInBackground - (Optional) {String} If set, either use default --hidden arg or specified one. - // :mac - (Optional) {Object} - // :useLaunchAgent - (Optional) {Boolean} If `true`, use filed-based Launch Agent. Otherwise use AppleScript - // to add Login Item - // :extraArguments - (Optional) {Array} - constructor(init) { - this.appName = init.appName; - this.appPath = init.appPath; - this.options = init.options; - } + // init - {Object} + // :appName - {String} + // :appPath - {String} + // :options - {Object} + // :launchInBackground - (Optional) {String} If set, either use default --hidden arg or specified one. + // :mac - (Optional) {Object} + // :useLaunchAgent - (Optional) {Boolean} If `true`, use filed-based Launch Agent. Otherwise use AppleScript + // to add Login Item + // :extraArguments - (Optional) {Array} + constructor(init) { + this.appName = init.appName; + this.appPath = init.appPath; + this.options = init.options; + } - // Returns a Promise - enable() { - throw new Error('enable() not implemented'); - } + // Returns a Promise + enable() { + throw new Error('enable() not implemented'); + } - // Returns a Promise - disable() { - throw new Error('disable() not implemented'); - } + // Returns a Promise + disable() { + throw new Error('disable() not implemented'); + } - // Returns a Promise which resolves to a {Boolean} - isEnabled() { - throw new Error('isEnable() not implemented'); - } + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + throw new Error('isEnable() not implemented'); + } } diff --git a/src/library/autoLaunchAPI/autoLaunchAPILinux.js b/src/library/autoLaunchAPI/autoLaunchAPILinux.js index ad6e8b5..419f6be 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPILinux.js +++ b/src/library/autoLaunchAPI/autoLaunchAPILinux.js @@ -1,7 +1,7 @@ import path from 'node:path'; import untildify from 'untildify'; import * as fileBasedUtilities from '../fileBasedUtilities.js'; -import AutoLaunchAPI from './autoLaunchAPI.js' +import AutoLaunchAPI from './autoLaunchAPI.js'; const LINUX_AUTOSTART_DIR = '~/.config/autostart'; const LINUX_DESKTOP = ` @@ -16,76 +16,76 @@ Terminal=false `; export default class AutoLaunchAPILinux extends AutoLaunchAPI { - /* Public */ - - constructor(init) { - super(init); - this.appPath = this.#fixAppPath(); + /* Public */ + + constructor(init) { + super(init); + this.appPath = this.#fixAppPath(); + } + + // Returns a Promise + enable() { + const hiddenArg = this.options.launchInBackground; + const extraArgs = this.options.extraArguments; + const programArguments = []; + + // Manage arguments + if (hiddenArg) { + programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden'); } - - // Returns a Promise - enable() { - const hiddenArg = this.options.launchInBackground; - const extraArgs = this.options.extraArguments; - const programArguments = []; - - // Manage arguments - if (hiddenArg) { - programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden'); - } - if (extraArgs) { - programArguments.push(extraArgs); - } - const args = programArguments.join(' '); - - const desktop = LINUX_DESKTOP.trim() - .replace(/{{APP_NAME}}/g, this.appName) - .replace(/{{APP_PATH}}/g, this.appPath) - .replace(/{{ARGS}}/g, args); - - return fileBasedUtilities.createFile({ - directory: this.#getAutostartDirectory(), - filePath: this.#getDesktopFilePath(this.appName), - data: desktop - }); + if (extraArgs) { + programArguments.push(extraArgs); } - - // Returns a Promise - disable() { - return fileBasedUtilities.removeFile(this.#getDesktopFilePath()); + const args = programArguments.join(' '); + + const desktop = LINUX_DESKTOP.trim() + .replace(/{{APP_NAME}}/g, this.appName) + .replace(/{{APP_PATH}}/g, this.appPath) + .replace(/{{ARGS}}/g, args); + + return fileBasedUtilities.createFile({ + directory: this.#getAutostartDirectory(), + filePath: this.#getDesktopFilePath(this.appName), + data: desktop + }); + } + + // Returns a Promise + disable() { + return fileBasedUtilities.removeFile(this.#getDesktopFilePath()); + } + + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + return fileBasedUtilities.fileExists(this.#getDesktopFilePath()); + } + + /* Private */ + + // Returns a {String} + #getAutostartDirectory() { + return untildify(LINUX_AUTOSTART_DIR); + } + + // Returns a {String} + #getDesktopFilePath() { + return path.join(this.#getAutostartDirectory(), `${this.appName}.desktop`); + } + + // Returns a {String} + #fixAppPath() { + let execPath = this.appPath; + + // If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used. + // This will fail on the next launch, since AppImages are mount temporarily when executed + // in an everchanging mount folder. + if (process.env?.APPIMAGE != null) { + execPath = process.env.APPIMAGE; } - // Returns a Promise which resolves to a {Boolean} - isEnabled() { - return fileBasedUtilities.fileExists(this.#getDesktopFilePath()); - } - - /* Private */ - - // Returns a {String} - #getAutostartDirectory() { - return untildify(LINUX_AUTOSTART_DIR); - } + // As stated in the .desktop entry spec, Exec key's value must be properly escaped with reserved characters. + execPath = fileBasedUtilities.escapeFilePath(execPath); - // Returns a {String} - #getDesktopFilePath() { - return path.join(this.#getAutostartDirectory(), `${this.appName}.desktop`); - } - - // Returns a {String} - #fixAppPath() { - let execPath = this.appPath; - - // If this is an AppImage, the actual AppImage's file path must be used, otherwise the mount path will be used. - // This will fail on the next launch, since AppImages are mount temporarily when executed - // in an everchanging mount folder. - if (process.env?.APPIMAGE != null) { - execPath = process.env.APPIMAGE; - } - - // As stated in the .desktop entry spec, Exec key's value must be properly escaped with reserved characters. - execPath = fileBasedUtilities.escapeFilePath(execPath); - - return execPath; - } + return execPath; + } } diff --git a/src/library/autoLaunchAPI/autoLaunchAPIMac.js b/src/library/autoLaunchAPI/autoLaunchAPIMac.js index 1c9b2db..3675a45 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIMac.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIMac.js @@ -2,7 +2,7 @@ import applescript from 'applescript'; import path from 'node:path'; import untildify from 'untildify'; import * as fileBasedUtilities from '../fileBasedUtilities.js'; -import AutoLaunchAPI from './autoLaunchAPI.js' +import AutoLaunchAPI from './autoLaunchAPI.js'; const MAC_LAUNCHAGENTS_DIR = '~/Library/LaunchAgents/'; const MAC_PLIST_DATA = ` @@ -21,136 +21,137 @@ const MAC_PLIST_DATA = ` `; export default class AutoLaunchAPIMac extends AutoLaunchAPI { - /* Public */ - - constructor(init) { - super(init); - this.appName = this.#fixAppName(); - this.appPath = this.#fixAppPath(); + /* Public */ + + constructor(init) { + super(init); + this.appName = this.#fixAppName(); + this.appPath = this.#fixAppPath(); + } + + // Returns a Promise + enable() { + const hiddenArg = this.options.launchInBackground; + const extraArgs = this.options.extraArguments; + + // Add the file if we're using a Launch Agent + if (this.options.mac.useLaunchAgent) { + const programArguments = [this.appPath]; + + // Manage arguments + if (hiddenArg) { + programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden'); + } + if (extraArgs) { + programArguments.push(extraArgs); + } + const programArgumentsSection = programArguments + .map((argument) => ` ${argument}`) + .join('\n'); + const plistData = MAC_PLIST_DATA.trim() + .replace(/{{APP_NAME}}/g, this.appName) + .replace(/{{PROGRAM_ARGUMENTS_SECTION}}/g, programArgumentsSection); + + return fileBasedUtilities.createFile({ + directory: this.#getLaunchAgentsDirectory(), + filePath: this.#getPlistFilePath(), + data: plistData + }); } - // Returns a Promise - enable() { - const hiddenArg = this.options.launchInBackground; - const extraArgs = this.options.extraArguments; - - // Add the file if we're using a Launch Agent - if (this.options.mac.useLaunchAgent) { - const programArguments = [this.appPath]; - - // Manage arguments - if (hiddenArg) { - programArguments.push((hiddenArg !== true) ? hiddenArg : '--hidden'); - } - if (extraArgs) { - programArguments.push(extraArgs); - } - const programArgumentsSection = programArguments - .map((argument) => ` ${argument}`) - .join('\n'); - const plistData = MAC_PLIST_DATA.trim() - .replace(/{{APP_NAME}}/g, this.appName) - .replace(/{{PROGRAM_ARGUMENTS_SECTION}}/g, programArgumentsSection); - - return fileBasedUtilities.createFile({ - directory: this.#getLaunchAgentsDirectory(), - filePath: this.#getPlistFilePath(), - data: plistData - }); - } + // Otherwise, use default method; use AppleScript to tell System Events to add a Login Item - // Otherwise, use default method; use AppleScript to tell System Events to add a Login Item + const isHidden = hiddenArg ? 'true' : 'false'; + // TODO: Manage extra arguments + const properties = `{path:"${this.appPath}", hidden:${isHidden}, name:"${this.appName}"}`; - const isHidden = hiddenArg ? 'true' : 'false'; - // TODO: Manage extra arguments - const properties = `{path:"${this.appPath}", hidden:${isHidden}, name:"${this.appName}"}`; + return this.#execApplescriptCommand(`make login item at end with properties ${properties}`); + } - return this.#execApplescriptCommand(`make login item at end with properties ${properties}`); + // Returns a Promise + disable() { + // Delete the file if we're using a Launch Agent + if (this.options.mac.useLaunchAgent) { + return fileBasedUtilities.removeFile(this.#getPlistFilePath()); } - // Returns a Promise - disable() { - // Delete the file if we're using a Launch Agent - if (this.options.mac.useLaunchAgent) { - return fileBasedUtilities.removeFile(this.#getPlistFilePath()); - } - - // Otherwise remove the Login Item - return this.#execApplescriptCommand(`delete login item "${this.appName}"`); - } - - // Returns a Promise which resolves to a {Boolean} - isEnabled() { - // Check if the Launch Agent file exists - if (this.options.mac.useLaunchAgent) { - return fileBasedUtilities.fileExists(this.#getPlistFilePath()); - } - - // Otherwise check if a Login Item exists for our app - return this.#execApplescriptCommand('get the name of every login item') - .then((loginItems) => (loginItems != null) && Array.from(loginItems).includes(this.appName)); - } + // Otherwise remove the Login Item + return this.#execApplescriptCommand(`delete login item "${this.appName}"`); + } - /* Private */ - - // commandSuffix - {String} - // Returns a Promise - #execApplescriptCommand(commandSuffix) { - return new Promise((resolve, reject) => { - applescript.execString(`tell application "System Events" to ${commandSuffix}`, (err, result) => { - if (err != null) { - return reject(err); - } - return resolve(result); - }) - }); + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + // Check if the Launch Agent file exists + if (this.options.mac.useLaunchAgent) { + return fileBasedUtilities.fileExists(this.#getPlistFilePath()); } - // Returns a {String} - #getLaunchAgentsDirectory() { - return untildify(MAC_LAUNCHAGENTS_DIR); - } + // Otherwise check if a Login Item exists for our app + return this.#execApplescriptCommand('get the name of every login item') + .then((loginItems) => (loginItems != null) && Array.from(loginItems).includes(this.appName)); + } - // Returns a {String} - #getPlistFilePath() { - return path.join(this.#getLaunchAgentsDirectory(), `${this.appName}.plist`); - } + /* Private */ - // Corrects the path to point to the outer .app - // Returns a {String} - #fixAppPath() { - let execPath = this.appPath; - - // This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" - // (the default Electron app structure for example) - // It will also match apps whose outer app's basename is different to the rest but the inner app and executable's - // basenames are matching (a typical distributed NW.js app for example) - // Does not match when the three are different - // Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron - // executable in the outer app - execPath = execPath.replace(/(^.+?[^\/]+?\.app)\/Contents\/(Frameworks\/((\1|[^\/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1'); - - // When using a launch agent, it needs the inner executable path - if (!this.options.mac.useLaunchAgent) { - execPath = execPath.replace(/\.app\/Contents\/MacOS\/[^\/]*$/, '.app'); + // commandSuffix - {String} + // Returns a Promise + #execApplescriptCommand(commandSuffix) { + return new Promise((resolve, reject) => { + applescript.execString(`tell application "System Events" to ${commandSuffix}`, (err, result) => { + if (err != null) { + return reject(err); } - - return execPath; + return resolve(result); + }); + }); + } + + // Returns a {String} + #getLaunchAgentsDirectory() { + return untildify(MAC_LAUNCHAGENTS_DIR); + } + + // Returns a {String} + #getPlistFilePath() { + return path.join(this.#getLaunchAgentsDirectory(), `${this.appName}.plist`); + } + + // Corrects the path to point to the outer .app + // Returns a {String} + #fixAppPath() { + let execPath = this.appPath; + + // This will match apps whose inner app and executable's basename is the outer app's basename plus "Helper" + // (the default Electron app structure for example) + // It will also match apps whose outer app's basename is different to the rest but the inner app and executable's + // basenames are matching (a typical distributed NW.js app for example) + // Does not match when the three are different + // Also matches when the path is pointing not to the exectuable in the inner app at all but to the Electron + // executable in the outer app + // eslint-disable-next-line max-len + execPath = execPath.replace(/(^.+?[^/]+?\.app)\/Contents\/(Frameworks\/((\1|[^/]+?) Helper)\.app\/Contents\/MacOS\/\3|MacOS\/Electron)/, '$1'); + + // When using a launch agent, it needs the inner executable path + if (!this.options.mac.useLaunchAgent) { + execPath = execPath.replace(/\.app\/Contents\/MacOS\/[^/]*$/, '.app'); } - // Kept from Coffeescript, but should we honor the name given to autoLaunch or should we change it specifically for macOS? - // No explanation, see issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 - #fixAppName() { - let fixedName; + return execPath; + } - const tempPath = this.appPath.split('/'); + // Kept from Coffeescript, but should we honor the name given to autoLaunch or should we change it specifically for macOS? + // No explanation, see issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 + #fixAppName() { + let fixedName; - fixedName = tempPath[tempPath.length - 1]; - // Remove ".app" from the appName if it exists - if (fixedName.indexOf('.app', fixedName.length - '.app'.length) !== -1) { - fixedName = fixedName.substr(0, fixedName.length - '.app'.length); - } + const tempPath = this.appPath.split('/'); - return fixedName; + fixedName = tempPath[tempPath.length - 1]; + // Remove ".app" from the appName if it exists + if (fixedName.indexOf('.app', fixedName.length - '.app'.length) !== -1) { + fixedName = fixedName.substr(0, fixedName.length - '.app'.length); } + + return fixedName; + } } diff --git a/src/library/autoLaunchAPI/autoLaunchAPIWindows.js b/src/library/autoLaunchAPI/autoLaunchAPIWindows.js index 082657c..1ff625c 100644 --- a/src/library/autoLaunchAPI/autoLaunchAPIWindows.js +++ b/src/library/autoLaunchAPI/autoLaunchAPIWindows.js @@ -1,110 +1,104 @@ import fs from 'fs'; import path from 'path'; import Winreg from 'winreg'; -import AutoLaunchAPI from './autoLaunchAPI.js' +import AutoLaunchAPI from './autoLaunchAPI.js'; const regKey = new Winreg({ - hive: Winreg.HKCU, - key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' + hive: Winreg.HKCU, + key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' }); export default class AutoLaunchAPIWindows extends AutoLaunchAPI { - /* Public */ + /* Public */ - constructor(init) { - super(init); - } + constructor(init) { + super(init); + } - // Returns a Promise - enable() { - return new Promise((resolve, reject) => { - let args = ''; - let pathToAutoLaunchedApp; - const hiddenArg = this.options.launchInBackground; - const extraArgs = this.options.extraArguments; - const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe'); + // Returns a Promise + enable() { + return new Promise((resolve, reject) => { + let args = ''; + let pathToAutoLaunchedApp; + const hiddenArg = this.options.launchInBackground; + const extraArgs = this.options.extraArguments; + const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe'); - // 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 - if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) { - pathToAutoLaunchedApp = `"${updateDotExe}"`; - console.log('This application is built on Electron and is launched through: ', pathToAutoLaunchedApp); - args = ` --processStart "${path.basename(process.execPath)}"`; + // 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 + if (((process.versions != null ? process.versions.electron : undefined) != null) && fs.existsSync(updateDotExe)) { + pathToAutoLaunchedApp = `"${updateDotExe}"`; + args = ` --processStart "${path.basename(process.execPath)}"`; - // Manage arguments - if (hiddenArg || extraArgs) { - args += ' --process-start-args'; - if (hiddenArg) { - args += ` "${(hiddenArg !== true) ? hiddenArg : '--hidden'}"`; - } - // Add any extra arguments - if (extraArgs) { - args += ' "'; - args += extraArgs.join('" "'); - args += '"'; - } - } - } else { - // 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\\${this.appPath}`; - console.log('This application is an AppX and is launched through: ', pathToAutoLaunchedApp); - } else { - pathToAutoLaunchedApp = `"${this.appPath}"`; - console.log('This application is launched through: ', pathToAutoLaunchedApp); - } + // Manage arguments + if (hiddenArg || extraArgs) { + args += ' --process-start-args'; + if (hiddenArg) { + args += ` "${(hiddenArg !== true) ? hiddenArg : '--hidden'}"`; + } + // Add any extra arguments + if (extraArgs) { + args += ' "'; + args += extraArgs.join('" "'); + args += '"'; + } + } + } else { + // 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\\${this.appPath}`; + } else { + pathToAutoLaunchedApp = `"${this.appPath}"`; + } - // Manage arguments - if (hiddenArg) { - args = [(hiddenArg !== true) ? hiddenArg : ' --hidden']; - } - // Add any extra arguments - if (extraArgs) { - args += ' '; - args += extraArgs.join(' '); - } - } + // Manage arguments + if (hiddenArg) { + args = [(hiddenArg !== true) ? hiddenArg : ' --hidden']; + } + // Add any extra arguments + if (extraArgs) { + args += ' '; + args += extraArgs.join(' '); + } + } - regKey.set(this.appName, Winreg.REG_SZ, `"${pathToAutoLaunchedApp}"${args}`, (err) => { - if (err != null) { - console.log(err.message); - return reject(err); - } - return resolve(); - }); - }); - } + regKey.set(this.appName, Winreg.REG_SZ, `"${pathToAutoLaunchedApp}"${args}`, (err) => { + if (err != null) { + return reject(err); + } + return resolve(); + }); + }); + } - // Returns a Promise - disable() { - return new Promise((resolve, reject) => { - regKey.remove(this.appName, (err) => { - if (err != null) { - // 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') !== -1) { - return resolve(false); - } - console.log(err.message); - return reject(err); - } - return resolve(); - }); - }); - } + // Returns a Promise + disable() { + return new Promise((resolve, reject) => { + regKey.remove(this.appName, (err) => { + if (err != null) { + // 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') !== -1) { + return resolve(false); + } + return reject(err); + } + return resolve(); + }); + }); + } - // Returns a Promise which resolves to a {Boolean} - isEnabled() { - return new Promise((resolve, reject) => { - regKey.valueExists(this.appName, (err, exists) => { - if (err != null) { - console.log(err.message); - return resolve(false); - } - return resolve(exists); - }); - }); - } + // Returns a Promise which resolves to a {Boolean} + isEnabled() { + return new Promise((resolve) => { + regKey.valueExists(this.appName, (err, exists) => { + if (err != null) { + return resolve(false); + } + return resolve(exists); + }); + }); + } } diff --git a/src/library/autoLaunchHandler.js b/src/library/autoLaunchHandler.js index 090dad8..053d343 100644 --- a/src/library/autoLaunchHandler.js +++ b/src/library/autoLaunchHandler.js @@ -7,15 +7,15 @@ import AutoLaunchAPIWindows from './autoLaunchAPI/autoLaunchAPIWindows.js'; // Returns a AutoLaunchAPI object export default function autoLaunchHandler(options) { - if (/^win/.test(process.platform)) { - return new AutoLaunchAPIWindows(options); - } - if (/darwin/.test(process.platform)) { - return new AutoLaunchAPIMac(options); - } - if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - return new AutoLaunchAPILinux(options); - } + if (/^win/.test(process.platform)) { + return new AutoLaunchAPIWindows(options); + } + if (/darwin/.test(process.platform)) { + return new AutoLaunchAPIMac(options); + } + if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { + return new AutoLaunchAPILinux(options); + } - throw new Error('Unsupported platform'); + throw new Error('Unsupported platform'); } diff --git a/src/library/fileBasedUtilities.js b/src/library/fileBasedUtilities.js index 3bc76a3..9fa4737 100644 --- a/src/library/fileBasedUtilities.js +++ b/src/library/fileBasedUtilities.js @@ -8,61 +8,61 @@ import fs from 'fs'; // :filePath - {String} // :data - {String} // Returns a Promise -export function createFile({directory, filePath, data}) { - return new Promise((resolve, reject) => { - fs.mkdir(directory, { recursive: true }, (mkdirErr, path) => { - if (mkdirErr != null) { - return reject(mkdirErr); - } - return fs.writeFile(filePath, data, (writeErr) => { - if (writeErr != null) { - return reject(writeErr); - } - return resolve(); - }); - }); +export function createFile({ directory, filePath, data }) { + return new Promise((resolve, reject) => { + fs.mkdir(directory, { recursive: true }, (mkdirErr) => { + if (mkdirErr != null) { + return reject(mkdirErr); + } + return fs.writeFile(filePath, data, (writeErr) => { + if (writeErr != null) { + return reject(writeErr); + } + return resolve(); + }); }); + }); } // Verify auto-launch file exists or not // filePath - {String} // Returns a Promise export function fileExists(filePath) { - return new Promise((resolve, reject) => { - fs.stat(filePath, (err, stat) => { - if (err != null) { - return resolve(false); - } - return resolve(stat != null); - }); + return new Promise((resolve) => { + fs.stat(filePath, (err, stat) => { + if (err != null) { + return resolve(false); + } + return resolve(stat != null); }); + }); } // This is essentially disabling auto-launching // filePath - {String} // Returns a Promise export function removeFile(filePath) { - return new Promise((resolve, reject) => { - fs.stat(filePath, (statErr) => { - // If it doesn't exist, this is good so resolve - if (statErr != null) { - return resolve(); - } + return new Promise((resolve, reject) => { + fs.stat(filePath, (statErr) => { + // If it doesn't exist, this is good so resolve + if (statErr != null) { + return resolve(); + } - return fs.unlink(filePath, (unlinkErr) => { - if (unlinkErr != null) { - return reject(unlinkErr); - } - return resolve(); - }); - }); + return fs.unlink(filePath, (unlinkErr) => { + if (unlinkErr != null) { + return reject(unlinkErr); + } + return resolve(); + }); }); + }); } // Escape reserved characters in path // filePath - {String} // Returns {String} export function escapeFilePath(filePath) { - return filePath.replace(/(\s+)/g, '\\$1'); -// return filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://github.com/tc39/proposal-regex-escaping + return filePath.replace(/(\s+)/g, '\\$1'); + // return filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // https://github.com/tc39/proposal-regex-escaping } diff --git a/tests/helper.js b/tests/helper.js index eded865..ce5960e 100644 --- a/tests/helper.js +++ b/tests/helper.js @@ -1,27 +1,27 @@ export default class AutoLaunchHelper { - constructor(autoLaunch) { - this.autoLaunch = autoLaunch; - } + constructor(autoLaunch) { + this.autoLaunch = autoLaunch; + } - ensureEnabled() { - return this.autoLaunch.isEnabled().then((enabled) => { - if (!enabled) { - return this.autoLaunch.enable(); - } - return enabled; - }); - } + ensureEnabled() { + return this.autoLaunch.isEnabled().then((enabled) => { + if (!enabled) { + return this.autoLaunch.enable(); + } + return enabled; + }); + } - ensureDisabled() { - return this.autoLaunch.isEnabled().then((enabled) => { - if (enabled) { - return this.autoLaunch.disable(); - } - return enabled; - }); - } + ensureDisabled() { + return this.autoLaunch.isEnabled().then((enabled) => { + if (enabled) { + return this.autoLaunch.disable(); + } + return enabled; + }); + } - mockApi(stub) { - this.autoLaunch.api = stub; - } + mockApi(stub) { + this.autoLaunch.api = stub; + } } diff --git a/tests/test.js b/tests/test.js index e83af15..52ca9dd 100644 --- a/tests/test.js +++ b/tests/test.js @@ -11,273 +11,296 @@ let isPOSIX = false; let isMac = false; if (/^win/.test(process.platform)) { - executablePath = path.resolve(path.join('./tests/executables', 'GitHubSetup.exe')); + executablePath = path.resolve( + path.join('./tests/executables', 'GitHubSetup.exe') + ); } else if (/darwin/.test(process.platform)) { - isMac = true; - executablePath = '/Applications/Calculator.app'; -} else if ((/linux/.test(process.platform)) || (/freebsd/.test(process.platform))) { - followsXDG = true; - isPOSIX = true; - executablePath = path.resolve(path.join('./tests/executables', 'hv3-linux-x86')); + isMac = true; + executablePath = '/Applications/Calculator.app'; +} else if (/linux/.test(process.platform) || /freebsd/.test(process.platform)) { + followsXDG = true; + isPOSIX = true; + executablePath = path.resolve( + path.join('./tests/executables', 'hv3-linux-x86') + ); } -console.log('Executable being used for tests:', executablePath); - // General tests for all platforms describe('node-auto-launch', () => { - let autoLaunch = null; - let autoLaunchHelper = null; + let autoLaunch = null; + let autoLaunchHelper = null; + + beforeEach(() => { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePath, + options: { + mac: isMac ? { useLaunchAgent: true } : {}, + }, + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + }); + + describe('AutoLaunch constructor', () => { + it('should fail without a name', (done) => { + try { + autoLaunch = new AutoLaunch({ name: null }); + // Force the test to fail since error wasn't thrown + should.fail('It should have failed...'); + } catch (error) { + // Constructor threw Error, so test succeeded. + done(); + } + }); - beforeEach(() => { - autoLaunch = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePath, - options: { - mac: isMac ? { useLaunchAgent: true } : {} - } - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + it('should fail with an empty name', (done) => { + try { + autoLaunch = new AutoLaunch({ name: '' }); + // Force the test to fail since error wasn't thrown + should.fail('It should have failed...'); + } catch (error) { + // Constructor threw Error, so test succeeded. + done(); + } }); + }); - describe('AutoLaunch constructor', () => { - it('should fail without a name', function (done) { - try { - autoLaunch = new AutoLaunch({ name: null }); - // Force the test to fail since error wasn't thrown - should.fail('It should have failed...'); - } catch (error) { - // Constructor threw Error, so test succeeded. - done(); - } - }); + describe('.isEnabled', () => { + before(() => { + autoLaunchHelper.ensureDisabled(); + }); - it('should fail with an empty name', function (done) { - try { - autoLaunch = new AutoLaunch({ name: '' }); - // Force the test to fail since error wasn't thrown - should.fail('It should have failed...'); - } catch (error) { - // Constructor threw Error, so test succeeded. - done(); - } - }); + it('should be disabled', (done) => { + autoLaunch + .isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); + done(); + }) + .catch(done); }); - describe('.isEnabled', () => { - before(() => { - autoLaunchHelper.ensureDisabled(); - }); + after(() => { + autoLaunchHelper.ensureDisabled(); + }); + }); - it('should be disabled', function (done) { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(false); - done(); - }) - .catch(done); - }); + describe('.enable', () => { + before(() => { + autoLaunchHelper.ensureDisabled(); + }); - after(() => { - autoLaunchHelper.ensureDisabled(); - }); + it('should enable auto launch', (done) => { + autoLaunch.enable().then(() => { + autoLaunch + .isEnabled() + .then((enabled) => { + expect(enabled).to.equal(true); + done(); + }) + .catch(done); + }); }); - describe('.enable', () => { - before(() => { - autoLaunchHelper.ensureDisabled(); - }); + after(() => { + autoLaunchHelper.ensureDisabled(); + }); + }); - it('should enable auto launch', function (done) { - autoLaunch.enable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(true); - done(); - }) - .catch(done); - }); - }); + describe('.disable', () => { + beforeEach(() => { + autoLaunchHelper.ensureEnabled(); + }); - after(() => { - autoLaunchHelper.ensureDisabled(); - }); + it('should disable auto launch', (done) => { + autoLaunch.disable().then(() => { + autoLaunch + .isEnabled() + .then((enabled) => { + expect(enabled).to.equal(false); + done(); + }) + .catch(done); + }); }); - describe('.disable', () => { - beforeEach(() => { - autoLaunchHelper.ensureEnabled(); - }); + afterEach(() => { + autoLaunchHelper.ensureDisabled(); + }); + }); - it('should disable auto launch', function (done) { - autoLaunch.disable() - .then(() => { - autoLaunch.isEnabled() - .then((enabled) => { - expect(enabled).to.equal(false); - done(); - }) - .catch(done); - }); - }); + describe("Let's catch errors", () => { + it('should catch isEnable() errors', (done) => { + autoLaunchHelper.mockApi({ + isEnabled() { + return Promise.reject(); + }, + }); - afterEach(() => { - autoLaunchHelper.ensureDisabled(); - }); + autoLaunch.isEnabled().catch(done); }); - describe('Let\'s catch errors', () => { - it('should catch isEnable() errors', function (done) { - autoLaunchHelper.mockApi({ - isEnabled() { - return Promise.reject(); - } - }); + it('should catch enable() errors', (done) => { + autoLaunchHelper.mockApi({ + enable() { + return Promise.reject(); + }, + }); + autoLaunch.enable().catch(done); + }); + + it('should catch disable() errors', (done) => { + autoLaunchHelper.ensureEnabled(); + + autoLaunchHelper.mockApi({ + disable() { + return Promise.reject(); + }, + }); + autoLaunch.disable().catch(done); + }); + }); + + /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ + // See issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 + if (!isMac) { + describe('.appName', () => { + it('should honor name parameter', (done) => { + expect(autoLaunch.api.appName).to.equal('node-auto-launch test'); + done(); + }); + }); + } +}); + +// Let's test some POSIX/Linux/FreeBSD options +// They rely on reading and write files on POSIX based filesystems and +if (isPOSIX) { + describe('POSIX/Linux/FreeBSD tests', () => { + let autoLaunch = null; + let autoLaunchHelper = null; + const executablePathPosix = path.resolve('./path with spaces/'); - autoLaunch.isEnabled().catch(done); + // OSes/window managers that follow XDG (cross desktop group) specifications + if (followsXDG) { + describe('testing .appName', () => { + beforeEach(() => { + autoLaunch = null; + autoLaunchHelper = null; }); - it('should catch enable() errors', function (done) { - autoLaunchHelper.mockApi({ - enable() { - return Promise.reject(); + it('without space', (done) => { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch', + path: executablePathPosix, + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper.ensureDisabled(); + + autoLaunch + .enable() + .then(() => { + const desktopEntryPath = untildify( + path.join( + '~/.config/autostart/', + `${autoLaunch.api.appName}.desktop` + ) + ); + fs.stat(desktopEntryPath, (err, stats) => { + if (err) { + done(err); } - }); - autoLaunch.enable().catch(done); + expect(stats.isFile()).to.equal(true); + done(); + }); + }) + .catch(done); }); - it('should catch disable() errors', function (done) { - autoLaunchHelper.ensureEnabled(); - - autoLaunchHelper.mockApi({ - disable() { - return Promise.reject(); + it('with space', (done) => { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePathPosix, + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper.ensureDisabled(); + + autoLaunch + .enable() + .then(() => { + const desktopEntryPath = untildify( + path.join( + '~/.config/autostart/', + `${autoLaunch.api.appName}.desktop` + ) + ); + fs.stat(desktopEntryPath, (err, stats) => { + if (err) { + done(err); } - }); - autoLaunch.disable().catch(done); + expect(stats.isFile()).to.equal(true); + done(); + }); + }) + .catch(done); }); - }); - /* On macOS, we modify the appName (leftover from Coffeescript that had no explaination) */ - // See issue 92: https://github.com/Teamwork/node-auto-launch/issues/92 - if (!isMac) { - describe('.appName', () => { - it('should honor name parameter', function (done) { - expect(autoLaunch.api.appName).to.equal('node-auto-launch test'); + it('with capital letters', (done) => { + autoLaunch = new AutoLaunch({ + name: 'Node-Auto-Launch', + path: executablePathPosix, + }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + autoLaunchHelper.ensureDisabled(); + + autoLaunch + .enable() + .then(() => { + const desktopEntryPath = untildify( + path.join( + '~/.config/autostart/', + `${autoLaunch.api.appName}.desktop` + ) + ); + fs.stat(desktopEntryPath, (err, stats) => { + if (err) { + done(err); + } + expect(stats.isFile()).to.equal(true); done(); - }); + }); + }) + .catch(done); }); + + afterEach(() => { + autoLaunchHelper.ensureDisabled(); + }); + }); } -}); -// Let's test some POSIX/Linux/FreeBSD options -// They rely on reading and write files on POSIX based filesystems and -if (isPOSIX) { - describe('POSIX/Linux/FreeBSD tests', () => { - let autoLaunch = null; - let autoLaunchHelper = null; - const executablePathPosix = path.resolve('./path with spaces/'); - - // OSes/window managers that follow XDG (cross desktop group) specifications - if (followsXDG) { - describe('testing .appName', () => { - beforeEach(() => { - autoLaunch = null; - autoLaunchHelper = null; - }); - - it('without space', function (done) { - autoLaunch = new AutoLaunch({ - name: 'node-auto-launch', - path: executablePathPosix - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - autoLaunchHelper.ensureDisabled(); - - autoLaunch.enable() - .then(() => { - const desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunch.api.appName + '.desktop')); - fs.stat(desktopEntryPath, (err, stats) => { - if (err) { - done(err); - } - expect(stats.isFile()).to.equal(true); - done(); - }); - }) - .catch(done); - }); - - it('with space', function (done) { - autoLaunch = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePathPosix - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - autoLaunchHelper.ensureDisabled(); - - autoLaunch.enable() - .then(() => { - const desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunch.api.appName + '.desktop')); - fs.stat(desktopEntryPath, (err, stats) => { - if (err) { - done(err); - } - expect(stats.isFile()).to.equal(true); - done(); - }); - }) - .catch(done); - }); - - it('with capital letters', function (done) { - autoLaunch = new AutoLaunch({ - name: 'Node-Auto-Launch', - path: executablePathPosix - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - autoLaunchHelper.ensureDisabled(); - - autoLaunch.enable() - .then(() => { - const desktopEntryPath = untildify(path.join('~/.config/autostart/', autoLaunch.api.appName + '.desktop')); - fs.stat(desktopEntryPath, (err, stats) => { - if (err) { - done(err); - } - expect(stats.isFile()).to.equal(true); - done(); - }); - }) - .catch(done); - }); - - afterEach(() => { - autoLaunchHelper.ensureDisabled(); - }); - }); - } - - describe('testing path name', () => { - beforeEach(() => { - autoLaunch = null; - autoLaunchHelper = null; - }); - - it('should properly escape reserved caracters', function (done) { - autoLaunch = new AutoLaunch({ - name: 'node-auto-launch test', - path: executablePathPosix - }); - autoLaunchHelper = new AutoLaunchHelper(autoLaunch); - - expect(autoLaunch.api.appPath).to.equal(executablePathPosix.replace(/(\s+)/g, '\\$1')); - done(); - }); + describe('testing path name', () => { + beforeEach(() => { + autoLaunch = null; + autoLaunchHelper = null; + }); - afterEach(() => { - autoLaunchHelper.ensureDisabled(); - }); + it('should properly escape reserved caracters', (done) => { + autoLaunch = new AutoLaunch({ + name: 'node-auto-launch test', + path: executablePathPosix, }); + autoLaunchHelper = new AutoLaunchHelper(autoLaunch); + + expect(autoLaunch.api.appPath).to.equal( + executablePathPosix.replace(/(\s+)/g, '\\$1') + ); + done(); + }); + + afterEach(() => { + autoLaunchHelper.ensureDisabled(); + }); }); + }); }