From a6c1ffbe34518e281946c4f68de6722b492679ba Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 5 Jan 2024 11:32:18 -0800 Subject: [PATCH 01/45] feat: introduce a package for slack cli hooks --- packages/hooks/README.md | 8 + packages/hooks/package-lock.json | 23 +++ packages/hooks/package.json | 37 ++++ packages/hooks/src/check-update.js | 295 +++++++++++++++++++++++++++++ packages/hooks/src/get-hooks.js | 17 ++ packages/hooks/src/get-manifest.js | 80 ++++++++ packages/hooks/src/start.js | 43 +++++ 7 files changed, 503 insertions(+) create mode 100644 packages/hooks/README.md create mode 100644 packages/hooks/package-lock.json create mode 100644 packages/hooks/package.json create mode 100755 packages/hooks/src/check-update.js create mode 100755 packages/hooks/src/get-hooks.js create mode 100755 packages/hooks/src/get-manifest.js create mode 100755 packages/hooks/src/start.js diff --git a/packages/hooks/README.md b/packages/hooks/README.md new file mode 100644 index 000000000..c8020947e --- /dev/null +++ b/packages/hooks/README.md @@ -0,0 +1,8 @@ +# Slack CLI Hooks + +Node implementations of the contract between the [Slack CLI][cli] and +[Bolt for JavaScript][bolt]. + + +[bolt]: https://github.com/slackapi/bolt-js +[cli]: https://api.slack.com/automation/cli diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json new file mode 100644 index 000000000..3760ad3ea --- /dev/null +++ b/packages/hooks/package-lock.json @@ -0,0 +1,23 @@ +{ + "name": "@slack/hooks", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@slack/hooks", + "version": "0.0.1", + "license": "MIT", + "bin": { + "slack-cli-check-update": "src/check-update.js", + "slack-cli-get-hooks": "src/get-hooks.js", + "slack-cli-get-manifest": "src/get-manifest.js", + "slack-cli-start": "src/start.js" + }, + "engines": { + "node": ">= 18", + "npm": ">= 8.6.0" + } + } + } +} diff --git a/packages/hooks/package.json b/packages/hooks/package.json new file mode 100644 index 000000000..be70e057b --- /dev/null +++ b/packages/hooks/package.json @@ -0,0 +1,37 @@ +{ + "name": "@slack/hooks", + "version": "0.0.1", + "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", + "author": "Slack Technologies, LLC", + "license": "MIT", + "keywords": [ + "slack", + "cli", + "hooks" + ], + "main": "src/get-hooks.js", + "files": [ + "src/*.js" + ], + "engines": { + "node": ">= 18", + "npm": ">= 8.6.0" + }, + "repository": "slackapi/node-slack-sdk", + "homepage": "https://slack.dev/node-slack-sdk", + "publishConfig": { + "access": "public" + }, + "bugs": { + "url": "https://github.com/slackapi/node-slack-sdk/issues" + }, + "scripts": { + "test": "echo \"Tests are not implemented.\" && exit 0" + }, + "bin": { + "slack-cli-get-hooks": "./src/get-hooks.js", + "slack-cli-get-manifest": "./src/get-manifest.js", + "slack-cli-check-update": "./src/check-update.js", + "slack-cli-start": "./src/start.js" + } +} diff --git a/packages/hooks/src/check-update.js b/packages/hooks/src/check-update.js new file mode 100755 index 000000000..7f9d21246 --- /dev/null +++ b/packages/hooks/src/check-update.js @@ -0,0 +1,295 @@ +#!/usr/bin/env node --no-warnings +const fs = require('fs'); +const path = require('path'); +const util = require('util'); +const exec = util.promisify(require('child_process').exec); + +const SLACK_BOLT_SDK = '@slack/bolt'; +let checkUpdateExports = {}; + +/** + * Implements the check-update hook and looks for available SDK updates. + * Returns an object detailing info on Slack dependencies to pass up to the CLI. +*/ +(async function _(cwd) { + let updates = await checkForSDKUpdates(cwd); + console.log(JSON.stringify(updates)); // stdout +}(process.cwd())); + +/** + * Wraps and parses the output of the exec() function + * @param command the command being run by the exec() function + */ +async function execWrapper (command) { + const { stdout } = await exec(command); + return stdout.trim(); +} + +/** + * Checks for available SDK updates for specified dependencies, creates a version map, + * and then wraps everything up into a response to be passed to the CLI. + * @param cwd the current working directory + */ +async function checkForSDKUpdates(cwd) { + const { versionMap, inaccessibleFiles } = await createVersionMap(cwd); + const updateResp = createUpdateResp(versionMap, inaccessibleFiles); + return updateResp; +} + +/** + * Create a version map that contains each (Slack) dependency, detailing info about + * current and latest versions, as well as if breaking changes are present or if there + * were any errors with getting version retrieval. + * @param cwd the current working directory of the CLI project + */ +async function createVersionMap(cwd) { + const { versionMap, inaccessibleFiles } = await readProjectDependencies(cwd); + + if (versionMap && versionMap[SLACK_BOLT_SDK]) { + const current = versionMap[SLACK_BOLT_SDK].current || ''; + let latest = '', + error = null; + + try { + latest = await fetchLatestModuleVersion(SLACK_BOLT_SDK); + } catch (err) { + error = err; + } + const update = !!current && !!latest && current !== latest; + const breaking = hasBreakingChange(current, latest); + + versionMap[SLACK_BOLT_SDK] = { + ...versionMap[SLACK_BOLT_SDK], + latest, + update, + breaking, + error, + }; + } + + return { versionMap, inaccessibleFiles }; +} + +/** + * Reads project dependencies - cycles through project dependency files, extracts + * the listed dependencies, and adds it in to the version map with version info. + * @param cwd the current working directory of the CLI project + */ +async function readProjectDependencies(cwd) { + const versionMap = {}; + const { dependencyFile, inaccessibleFiles } = await gatherDependencyFiles( + cwd + ); + + try { + const [sdk, value] = + await checkUpdateExports.extractDependencies(dependencyFile.body, dependencyFile.name); + + if (sdk !== '' && sdk === SLACK_BOLT_SDK) { + versionMap[SLACK_BOLT_SDK] = { + name: sdk, + current: value.version, + }; + } + } catch (err) { + inaccessibleFiles.push({ name: dependencyFile.name, error: err }); + } + + return { versionMap, inaccessibleFiles }; +} + +/** + * Reads and parses JSON file - if it works, returns the file contents. + * If not, returns an empty object + * @param filePath the path of the file being read + */ +async function getJSON(filePath) { + let fileContents = {}; + try { + if (fs.existsSync(filePath)) { + fileContents = JSON.parse(fs.readFileSync(filePath, 'utf8')); + } else { + throw new Error('Cannot find a file at path ' + filePath); + } + } catch (err) { + throw new Error(err); + } + return fileContents; +} + +/** + * Gathers all related dependency files for the CLI project (package.json). + * @param cwd the current working directory of the CLI project + */ +async function gatherDependencyFiles(cwd) { + const { jsonDepFile, inaccessibleFiles } = await getJSONFiles(cwd); + const dependencyFile = jsonDepFile; + return { dependencyFile, inaccessibleFiles }; +} + +/** + * Gets the needed files that contain dependency info (package.json). + * @param cwd the current working directory of the CLI project + */ +async function getJSONFiles(cwd) { + const packageJSON = 'package.json'; + const jsonDepFile = {}; + const inaccessibleFiles = []; + + try { + const jsonFile = await getJSON(`${cwd}/${packageJSON}`); + const jsonIsParsable = + jsonFile && + typeof jsonFile === 'object' && + !Array.isArray(jsonFile) && + jsonFile.dependencies; + + if (jsonIsParsable) { + jsonDepFile.name = packageJSON; + jsonDepFile.body= jsonFile; + } + } catch (err) { + inaccessibleFiles.push({ name: packageJSON, error: err }); + } + + return { jsonDepFile, inaccessibleFiles }; +} + +/** + * Pulls dependencies from a given file and JSON structure. + * @param json JSON information that includes dependencies + * @param fileName name of the file that the dependency list is coming from + */ +checkUpdateExports.extractDependencies = async (json, fileName) => { + // Determine if the JSON passed is an object + const jsonIsParsable = + json !== null && typeof json === 'object' && !Array.isArray(json); + + if (jsonIsParsable) { + let boltCurrentVersion = ''; + if (json['dependencies']['@slack/bolt']) { + const boltCurrentVersionOutput = JSON.parse( + await checkUpdateExports.getBoltCurrentVersion() + ); + + if (boltCurrentVersionOutput !== '') { + boltCurrentVersion = + boltCurrentVersionOutput['dependencies']['@slack/bolt']['version']; + } + } + + return [ + '@slack/bolt', + { + version: boltCurrentVersion, + }, + ]; + } + + return []; +}; + +/** + * Gets the latest module version. + * @param moduleName the module that the latest version is being queried for + */ +async function fetchLatestModuleVersion(moduleName) { + let command = ''; + if (moduleName === '@slack/bolt') { + command = `npm info ${moduleName} version --tag next-gen`; + } else if (moduleName === '@slack/deno-slack-sdk') { + command = `npm info ${moduleName} version --tag latest`; + } + const stdout = await execWrapper(command); + + return stdout; +} + +/** + * Checks if a dependency's upgrade from a current to the latest version will cause a + * breaking change. + * @param current current dependency version in project + * @param latest most up-to-date dependency version available on NPM + */ +function hasBreakingChange(current, latest) { + return current !== latest; +} + +/** + * Creates the update response - returns an object in the expected response format. + * @param versionMap version map of checked dependencies, current versions, and info on upgrade + breaking changes + * @param inaccessibleFiles array of files that could not be read or accessed + */ +function createUpdateResp(versionMap, inaccessibleFiles) { + const name = 'the Slack SDK'; + const releases = []; + const url = 'https://api.slack.com/future/changelog'; + const fileErrorMsg = createFileErrorMsg(inaccessibleFiles); + + let error = null; + let errorMsg = ''; + let message = ''; + + + // Output information for each dependency + for (const sdk of Object.values(versionMap)) { + // Dependency has an update OR the fetch of update failed + if (sdk) { + releases.push(sdk); + + // Add the dependency that failed to be fetched to the top-level error message + if (sdk.error && sdk.error.message) { + errorMsg += errorMsg + ? `, ${sdk}` + : `An error occurred fetching updates for the following packages: ${sdk.name}`; + } + } + } + + // Surface release notes for breaking changes + if (releases && releases[0] && releases[0].breaking) { + message = `Learn more about the breaking change at https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@${releases[0].latest}` + } + + // If there were issues accessing dependency files, append error message(s) + if (inaccessibleFiles.length) { + errorMsg += errorMsg ? `\n\n ${fileErrorMsg}` : fileErrorMsg; + } + + if (errorMsg) { + error = { message: errorMsg }; + } + + return { + name, + message, + releases, + url, + error, + }; +} + +/** + * Returns error when dependency files cannot be read. + * @param inaccessibleFiles array of files that could not be read or accessed + */ +function createFileErrorMsg(inaccessibleFiles) { + let fileErrorMsg = ''; + + // There were issues with reading some of the files that were found + for (const file of inaccessibleFiles) { + fileErrorMsg += fileErrorMsg + ? `\n ${file.name}: ${file.error.message}` + : `An error occurred while reading the following files: \n\n ${file.name}: ${file.error.message}`; + } + + return fileErrorMsg; +} + +/** + * Queries for current Bolt version of the project. + */ +checkUpdateExports.getBoltCurrentVersion = async () => { + const stdout = await execWrapper('npm list @slack/bolt --depth=0 --json'); + return stdout; +}; \ No newline at end of file diff --git a/packages/hooks/src/get-hooks.js b/packages/hooks/src/get-hooks.js new file mode 100755 index 000000000..d8668e18d --- /dev/null +++ b/packages/hooks/src/get-hooks.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node +console.log(JSON.stringify({ + hooks: { + 'get-manifest': 'npx -q --no-install -p @slack/bolt slack-cli-get-manifest', + 'check-update': 'npx -q --no-install -p @slack/bolt slack-cli-check-update', + start: 'npx -q --no-install -p @slack/bolt slack-cli-start', + }, + config: { + watch: { + 'filter-regex': '^manifest\\.(ts|js|json)$', + paths: [ + '.', + ], + }, + 'sdk-managed-connection-enabled': true, + }, +})); \ No newline at end of file diff --git a/packages/hooks/src/get-manifest.js b/packages/hooks/src/get-manifest.js new file mode 100755 index 000000000..303ba8afc --- /dev/null +++ b/packages/hooks/src/get-manifest.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); + +/** + * Implements the get-manifest script hook required by the Slack CLI + * Returns a manifest JSON string to stdout. +*/ +(function _(cwd) { + let manifest = getManifestData(cwd); + console.log(JSON.stringify(manifest)); +}(process.cwd())); + +/** + * Returns manifest data + * @param searchDir path to begin searching at + */ +function getManifestData(searchDir) { + const manifestJSON = readManifestJSONFile(searchDir, 'manifest.json'); + + if (!manifestJSON) { + const msg = 'Unable to find a manifest file in this project'; + throw new Error(msg); + } + + return manifestJSON; +} + +/** + * Returns a manifest.json if it exists, null otherwise + * @param searchDir typically current working directory + * @param filename file to search for + */ +function readManifestJSONFile(searchDir, filename) { + let jsonFilePath, manifestJSON; + + try { + jsonFilePath = find(searchDir, filename); + if (fs.existsSync(jsonFilePath)) { + manifestJSON = JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); + } + } catch (error) { + console.error(error) + return null; + } + + return manifestJSON; +} + +/** + * Search for provided file path. + * Returns full path when filename is found or null if no file found. + * @param currentPath string of current path + * @param targetFilename filename to match + * @returns full file path string relative to starting path or null + * */ +function find(currentPath, targetFilename) { + // TODO Cache searched paths and check that they haven't been explored already + // This guards against rare edge case of a subdir in the file tree which is + // symlinked back to root or in such a way that creates a cycle. Can also implement + // max depth check. + if (currentPath.endsWith(`/${targetFilename}`)) { + return currentPath; + } + + if (fs.existsSync(currentPath) && fs.lstatSync(currentPath).isDirectory()) { + let foundEntry; + const dirents = fs.readdirSync(currentPath); + for (const entry of dirents) { + if (entry !== 'node_modules') { + let newPath = path.resolve(currentPath, entry); + foundEntry = find(newPath, targetFilename); + if (foundEntry) { + return foundEntry; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/packages/hooks/src/start.js b/packages/hooks/src/start.js new file mode 100755 index 000000000..c3d1bfbe5 --- /dev/null +++ b/packages/hooks/src/start.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node +const { spawn } = require('child_process'); +const path = require('path'); +const fs = require('fs'); +const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf-8')); + +// Run script hook verifies that requirements for running an App in +// in developerMode (via Socket Mode) are met +(function _(cwd, customPath) { + // TODO - Format so that its less miss-able in output + console.log('Preparing local run in developer mode (Socket Mode)'); + // Check required local run tokens + validate(); + + // tries the provided path, then package.json main, then defaults to index.js in the current + // working directory + const pkgJSONDefault = 'index.js'; + const fullPath = path.resolve(cwd, customPath ? customPath : pkgJSONMain ? pkgJSONMain : pkgJSONDefault); + console.log(fullPath); + + // Kick off a subprocess to run the app in development mode + const app = spawn('node', [`${fullPath}`]); + app.stdout.setEncoding('utf-8'); + app.stdout.on('data', (data) => { + process.stdout.write(data); + }); + app.stderr.on('data', (data) => { + process.stderr.write(data); + }); + + app.on('close', (code) => { + console.log(`bolt-app local run exited with code ${code}`); + }); +}(process.cwd(), process.env.SLACK_CLI_CUSTOM_FILE_PATH)); + +function validate() { + if (!process.env.SLACK_CLI_XOXB) { + throw new Error('Missing local run bot token. Please see slack-cli maintainers to troubleshoot.'); + } + if (!process.env.SLACK_CLI_XAPP) { + throw new Error('Missing local run app token. Please see slack-cli maintainers to troubleshoot'); + } +} \ No newline at end of file From 791d35eb730ad0f2c1e278b3b20922ddb7545fa5 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Mon, 8 Jan 2024 17:21:25 -0800 Subject: [PATCH 02/45] fix: correct errors in hooks package before publishing --- packages/hooks/package.json | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/hooks/package.json b/packages/hooks/package.json index be70e057b..de9aebd93 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -17,7 +17,10 @@ "node": ">= 18", "npm": ">= 8.6.0" }, - "repository": "slackapi/node-slack-sdk", + "repository": { + "type": "git", + "url": "git+https://github.com/slackapi/node-slack-sdk.git" + }, "homepage": "https://slack.dev/node-slack-sdk", "publishConfig": { "access": "public" @@ -29,9 +32,9 @@ "test": "echo \"Tests are not implemented.\" && exit 0" }, "bin": { - "slack-cli-get-hooks": "./src/get-hooks.js", - "slack-cli-get-manifest": "./src/get-manifest.js", - "slack-cli-check-update": "./src/check-update.js", - "slack-cli-start": "./src/start.js" + "slack-cli-get-hooks": "src/get-hooks.js", + "slack-cli-get-manifest": "src/get-manifest.js", + "slack-cli-check-update": "src/check-update.js", + "slack-cli-start": "src/start.js" } } From 49e6f3de919bb20f48c7d6f311732e9c2409df73 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Mon, 8 Jan 2024 20:55:54 -0800 Subject: [PATCH 03/45] feat: convert scripts to typescript for type safety - feat: introduce shared linter configurations - fix: fix common linting errors - refactor: update checking for the check update hook - build: add a build step to transpile typescript --- lint-configs/.eslintrc.js | 3 + packages/hooks/.eslintignore | 1 + packages/hooks/.eslintrc.js | 1 + packages/hooks/.gitignore | 6 + packages/hooks/package-lock.json | 3205 ++++++++++++++++- packages/hooks/package.json | 28 +- packages/hooks/src/check-update.js | 295 -- packages/hooks/src/check-update.ts | 326 ++ packages/hooks/src/get-hooks.js | 17 - packages/hooks/src/get-hooks.ts | 19 + .../src/{get-manifest.js => get-manifest.ts} | 68 +- packages/hooks/src/{start.js => start.ts} | 23 +- packages/hooks/tsconfig.eslint.json | 1 + packages/hooks/tsconfig.json | 35 + 14 files changed, 3657 insertions(+), 371 deletions(-) create mode 120000 packages/hooks/.eslintignore create mode 120000 packages/hooks/.eslintrc.js create mode 100644 packages/hooks/.gitignore delete mode 100755 packages/hooks/src/check-update.js create mode 100755 packages/hooks/src/check-update.ts delete mode 100755 packages/hooks/src/get-hooks.js create mode 100755 packages/hooks/src/get-hooks.ts rename packages/hooks/src/{get-manifest.js => get-manifest.ts} (61%) rename packages/hooks/src/{start.js => start.ts} (71%) create mode 120000 packages/hooks/tsconfig.eslint.json create mode 100644 packages/hooks/tsconfig.json diff --git a/lint-configs/.eslintrc.js b/lint-configs/.eslintrc.js index a1ebd902c..081a6591f 100644 --- a/lint-configs/.eslintrc.js +++ b/lint-configs/.eslintrc.js @@ -65,6 +65,9 @@ module.exports = { // Allow safe references to functions before the declaration. Overrides AirBnB config. Not located in the override // section below because a distinct override is necessary in TypeScript files. 'no-use-before-define': ['error', 'nofunc'], + + // Allow scripts for hooks implementations. + 'node/shebang': 'off', }, overrides: [ diff --git a/packages/hooks/.eslintignore b/packages/hooks/.eslintignore new file mode 120000 index 000000000..5169d53c8 --- /dev/null +++ b/packages/hooks/.eslintignore @@ -0,0 +1 @@ +../../lint-configs/.eslintignore \ No newline at end of file diff --git a/packages/hooks/.eslintrc.js b/packages/hooks/.eslintrc.js new file mode 120000 index 000000000..5962fa3ca --- /dev/null +++ b/packages/hooks/.eslintrc.js @@ -0,0 +1 @@ +../../lint-configs/.eslintrc.js \ No newline at end of file diff --git a/packages/hooks/.gitignore b/packages/hooks/.gitignore new file mode 100644 index 000000000..33ce574cc --- /dev/null +++ b/packages/hooks/.gitignore @@ -0,0 +1,6 @@ +# node / npm stuff +/node_modules +package-lock.json + +# build products +/dist diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json index 3760ad3ea..a445d5a2f 100644 --- a/packages/hooks/package-lock.json +++ b/packages/hooks/package-lock.json @@ -1,23 +1,3216 @@ { "name": "@slack/hooks", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@slack/hooks", - "version": "0.0.1", + "version": "0.0.2", "license": "MIT", "bin": { - "slack-cli-check-update": "src/check-update.js", - "slack-cli-get-hooks": "src/get-hooks.js", - "slack-cli-get-manifest": "src/get-manifest.js", - "slack-cli-start": "src/start.js" + "slack-cli-check-update": "dist/check-update.js", + "slack-cli-get-hooks": "dist/get-hooks.js", + "slack-cli-get-manifest": "dist/get-manifest.js", + "slack-cli-start": "dist/start.js" + }, + "devDependencies": { + "@types/node": "^20.10.6", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-plugin-jsdoc": "^48.0.2", + "eslint-plugin-node": "^11.1.0", + "shx": "^0.3.4" }, "engines": { "node": ">= 18", "npm": ">= 8.6.0" } + }, + "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, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "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/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, + "peer": 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/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "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, + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true, + "peer": true + }, + "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/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "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, + "peer": true + }, + "node_modules/@types/node": { + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", + "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/type-utils": "6.17.0", + "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", + "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", + "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", + "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/utils": "6.17.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", + "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", + "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", + "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", + "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.17.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "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, + "peer": 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, + "peer": 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, + "peer": 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, + "peer": 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-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": 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, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "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, + "peer": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "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, + "peer": 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, + "peer": 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.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "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/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "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, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "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, + "peer": 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/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, + "peer": 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, + "peer": true + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "engines": { + "node": ">= 12.0.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/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/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, + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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/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, + "peer": true + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "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, + "peer": 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/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": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@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-config-airbnb-typescript": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", + "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, + "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, + "peer": 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, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "peer": 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, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.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, + "peer": 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, + "peer": 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, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "48.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.0.2.tgz", + "integrity": "sha512-CBFl5Jc7+jlV36RwDm+PQ8Uw5r28pn2/uW/OaB+Gw5bFwn4Py/1eYMZ3hGf9S4meUFZ/sRvS+hVif2mRAp6WqQ==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "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, + "peer": 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-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/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, + "peer": 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/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/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, + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "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/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": 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, + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/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/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, + "peer": 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, + "peer": true + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "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, + "peer": 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, + "peer": 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-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "peer": 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.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true, + "peer": 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": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "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/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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, + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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, + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "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.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/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, + "peer": 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, + "peer": 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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "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-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-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-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-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.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "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, + "peer": 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.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "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.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "peer": 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, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "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, + "peer": 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, + "peer": 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, + "peer": true + }, + "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, + "peer": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "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, + "peer": 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, + "peer": 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, + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "peer": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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/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/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/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.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "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, + "peer": 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, + "peer": 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, + "peer": 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, + "peer": 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, + "peer": 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, + "peer": 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/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/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, + "peer": 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, + "peer": 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/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "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, + "peer": 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, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.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/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "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, + "peer": 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, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dev": true, + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "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, + "peer": 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, + "peer": 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, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "peer": true + }, + "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": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "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, + "peer": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "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, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "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": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "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, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "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, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "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, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/packages/hooks/package.json b/packages/hooks/package.json index de9aebd93..5e0e8759f 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/hooks", - "version": "0.0.1", + "version": "0.0.2", "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", @@ -9,9 +9,9 @@ "cli", "hooks" ], - "main": "src/get-hooks.js", + "main": "dist/get-hooks.js", "files": [ - "src/*.js" + "dist/*.js" ], "engines": { "node": ">= 18", @@ -29,12 +29,26 @@ "url": "https://github.com/slackapi/node-slack-sdk/issues" }, "scripts": { + "clean": "shx rm -rf ./dist", + "prebuild": "npm run clean", + "build": "tsc", + "postbuild": "shx chmod +x dist/*.js", + "lint": "eslint --ext .ts src", "test": "echo \"Tests are not implemented.\" && exit 0" }, "bin": { - "slack-cli-get-hooks": "src/get-hooks.js", - "slack-cli-get-manifest": "src/get-manifest.js", - "slack-cli-check-update": "src/check-update.js", - "slack-cli-start": "src/start.js" + "slack-cli-get-hooks": "dist/get-hooks.js", + "slack-cli-get-manifest": "dist/get-manifest.js", + "slack-cli-check-update": "dist/check-update.js", + "slack-cli-start": "dist/start.js" + }, + "devDependencies": { + "@types/node": "^20.10.6", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-plugin-jsdoc": "^48.0.2", + "eslint-plugin-node": "^11.1.0", + "shx": "^0.3.4" } } diff --git a/packages/hooks/src/check-update.js b/packages/hooks/src/check-update.js deleted file mode 100755 index 7f9d21246..000000000 --- a/packages/hooks/src/check-update.js +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env node --no-warnings -const fs = require('fs'); -const path = require('path'); -const util = require('util'); -const exec = util.promisify(require('child_process').exec); - -const SLACK_BOLT_SDK = '@slack/bolt'; -let checkUpdateExports = {}; - -/** - * Implements the check-update hook and looks for available SDK updates. - * Returns an object detailing info on Slack dependencies to pass up to the CLI. -*/ -(async function _(cwd) { - let updates = await checkForSDKUpdates(cwd); - console.log(JSON.stringify(updates)); // stdout -}(process.cwd())); - -/** - * Wraps and parses the output of the exec() function - * @param command the command being run by the exec() function - */ -async function execWrapper (command) { - const { stdout } = await exec(command); - return stdout.trim(); -} - -/** - * Checks for available SDK updates for specified dependencies, creates a version map, - * and then wraps everything up into a response to be passed to the CLI. - * @param cwd the current working directory - */ -async function checkForSDKUpdates(cwd) { - const { versionMap, inaccessibleFiles } = await createVersionMap(cwd); - const updateResp = createUpdateResp(versionMap, inaccessibleFiles); - return updateResp; -} - -/** - * Create a version map that contains each (Slack) dependency, detailing info about - * current and latest versions, as well as if breaking changes are present or if there - * were any errors with getting version retrieval. - * @param cwd the current working directory of the CLI project - */ -async function createVersionMap(cwd) { - const { versionMap, inaccessibleFiles } = await readProjectDependencies(cwd); - - if (versionMap && versionMap[SLACK_BOLT_SDK]) { - const current = versionMap[SLACK_BOLT_SDK].current || ''; - let latest = '', - error = null; - - try { - latest = await fetchLatestModuleVersion(SLACK_BOLT_SDK); - } catch (err) { - error = err; - } - const update = !!current && !!latest && current !== latest; - const breaking = hasBreakingChange(current, latest); - - versionMap[SLACK_BOLT_SDK] = { - ...versionMap[SLACK_BOLT_SDK], - latest, - update, - breaking, - error, - }; - } - - return { versionMap, inaccessibleFiles }; -} - -/** - * Reads project dependencies - cycles through project dependency files, extracts - * the listed dependencies, and adds it in to the version map with version info. - * @param cwd the current working directory of the CLI project - */ -async function readProjectDependencies(cwd) { - const versionMap = {}; - const { dependencyFile, inaccessibleFiles } = await gatherDependencyFiles( - cwd - ); - - try { - const [sdk, value] = - await checkUpdateExports.extractDependencies(dependencyFile.body, dependencyFile.name); - - if (sdk !== '' && sdk === SLACK_BOLT_SDK) { - versionMap[SLACK_BOLT_SDK] = { - name: sdk, - current: value.version, - }; - } - } catch (err) { - inaccessibleFiles.push({ name: dependencyFile.name, error: err }); - } - - return { versionMap, inaccessibleFiles }; -} - -/** - * Reads and parses JSON file - if it works, returns the file contents. - * If not, returns an empty object - * @param filePath the path of the file being read - */ -async function getJSON(filePath) { - let fileContents = {}; - try { - if (fs.existsSync(filePath)) { - fileContents = JSON.parse(fs.readFileSync(filePath, 'utf8')); - } else { - throw new Error('Cannot find a file at path ' + filePath); - } - } catch (err) { - throw new Error(err); - } - return fileContents; -} - -/** - * Gathers all related dependency files for the CLI project (package.json). - * @param cwd the current working directory of the CLI project - */ -async function gatherDependencyFiles(cwd) { - const { jsonDepFile, inaccessibleFiles } = await getJSONFiles(cwd); - const dependencyFile = jsonDepFile; - return { dependencyFile, inaccessibleFiles }; -} - -/** - * Gets the needed files that contain dependency info (package.json). - * @param cwd the current working directory of the CLI project - */ -async function getJSONFiles(cwd) { - const packageJSON = 'package.json'; - const jsonDepFile = {}; - const inaccessibleFiles = []; - - try { - const jsonFile = await getJSON(`${cwd}/${packageJSON}`); - const jsonIsParsable = - jsonFile && - typeof jsonFile === 'object' && - !Array.isArray(jsonFile) && - jsonFile.dependencies; - - if (jsonIsParsable) { - jsonDepFile.name = packageJSON; - jsonDepFile.body= jsonFile; - } - } catch (err) { - inaccessibleFiles.push({ name: packageJSON, error: err }); - } - - return { jsonDepFile, inaccessibleFiles }; -} - -/** - * Pulls dependencies from a given file and JSON structure. - * @param json JSON information that includes dependencies - * @param fileName name of the file that the dependency list is coming from - */ -checkUpdateExports.extractDependencies = async (json, fileName) => { - // Determine if the JSON passed is an object - const jsonIsParsable = - json !== null && typeof json === 'object' && !Array.isArray(json); - - if (jsonIsParsable) { - let boltCurrentVersion = ''; - if (json['dependencies']['@slack/bolt']) { - const boltCurrentVersionOutput = JSON.parse( - await checkUpdateExports.getBoltCurrentVersion() - ); - - if (boltCurrentVersionOutput !== '') { - boltCurrentVersion = - boltCurrentVersionOutput['dependencies']['@slack/bolt']['version']; - } - } - - return [ - '@slack/bolt', - { - version: boltCurrentVersion, - }, - ]; - } - - return []; -}; - -/** - * Gets the latest module version. - * @param moduleName the module that the latest version is being queried for - */ -async function fetchLatestModuleVersion(moduleName) { - let command = ''; - if (moduleName === '@slack/bolt') { - command = `npm info ${moduleName} version --tag next-gen`; - } else if (moduleName === '@slack/deno-slack-sdk') { - command = `npm info ${moduleName} version --tag latest`; - } - const stdout = await execWrapper(command); - - return stdout; -} - -/** - * Checks if a dependency's upgrade from a current to the latest version will cause a - * breaking change. - * @param current current dependency version in project - * @param latest most up-to-date dependency version available on NPM - */ -function hasBreakingChange(current, latest) { - return current !== latest; -} - -/** - * Creates the update response - returns an object in the expected response format. - * @param versionMap version map of checked dependencies, current versions, and info on upgrade + breaking changes - * @param inaccessibleFiles array of files that could not be read or accessed - */ -function createUpdateResp(versionMap, inaccessibleFiles) { - const name = 'the Slack SDK'; - const releases = []; - const url = 'https://api.slack.com/future/changelog'; - const fileErrorMsg = createFileErrorMsg(inaccessibleFiles); - - let error = null; - let errorMsg = ''; - let message = ''; - - - // Output information for each dependency - for (const sdk of Object.values(versionMap)) { - // Dependency has an update OR the fetch of update failed - if (sdk) { - releases.push(sdk); - - // Add the dependency that failed to be fetched to the top-level error message - if (sdk.error && sdk.error.message) { - errorMsg += errorMsg - ? `, ${sdk}` - : `An error occurred fetching updates for the following packages: ${sdk.name}`; - } - } - } - - // Surface release notes for breaking changes - if (releases && releases[0] && releases[0].breaking) { - message = `Learn more about the breaking change at https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@${releases[0].latest}` - } - - // If there were issues accessing dependency files, append error message(s) - if (inaccessibleFiles.length) { - errorMsg += errorMsg ? `\n\n ${fileErrorMsg}` : fileErrorMsg; - } - - if (errorMsg) { - error = { message: errorMsg }; - } - - return { - name, - message, - releases, - url, - error, - }; -} - -/** - * Returns error when dependency files cannot be read. - * @param inaccessibleFiles array of files that could not be read or accessed - */ -function createFileErrorMsg(inaccessibleFiles) { - let fileErrorMsg = ''; - - // There were issues with reading some of the files that were found - for (const file of inaccessibleFiles) { - fileErrorMsg += fileErrorMsg - ? `\n ${file.name}: ${file.error.message}` - : `An error occurred while reading the following files: \n\n ${file.name}: ${file.error.message}`; - } - - return fileErrorMsg; -} - -/** - * Queries for current Bolt version of the project. - */ -checkUpdateExports.getBoltCurrentVersion = async () => { - const stdout = await execWrapper('npm list @slack/bolt --depth=0 --json'); - return stdout; -}; \ No newline at end of file diff --git a/packages/hooks/src/check-update.ts b/packages/hooks/src/check-update.ts new file mode 100755 index 000000000..41cd8bfe2 --- /dev/null +++ b/packages/hooks/src/check-update.ts @@ -0,0 +1,326 @@ +#!/usr/bin/env node +import fs from 'fs'; +import util from 'util'; +import childProcess from 'child_process'; + +const exec = util.promisify(childProcess.exec); + +const SLACK_BOLT_SDK = '@slack/bolt'; +const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; +const SLACK_CLI_HOOKS = '@slack/hooks'; + +interface UpdateInfo { + /** Overall package identifier */ + name: string; + /** Collection of new releases */ + releases: ReleaseInfo[]; + /** Details about any updates */ + message: string | undefined; + /** Additional notes to inspect */ + url: string | undefined; + /** Information of happened failures */ + error: ErrorInfo | undefined; +} + +interface ReleaseInfo { + /** Dependency identifier on known registry. */ + name: string; + /** Version present in the current project. */ + current: string | undefined; + /** Most recent version available to download. */ + latest: string | undefined; + /** If latest version is newer than current. */ + update: boolean; + /** If latest version requires a major bump. */ + breaking: boolean; + /** Additional information for the dependency. */ + message: string | undefined; + /** Web address containing update information. */ + url: string | undefined; + /** Information of failures found gathering. */ + error: ErrorInfo | undefined; +} + +interface ErrorInfo { + message: string; +} + +/** + * Mappings from dependencies to installed packages for the project. + */ +interface ProjectDependencies { + /** The file contianing package information. Often package.json. */ + fileName: string; + /** Pairs of packages and the matching values in a package.json. */ + dependencies: Record; +} + +/** + * File that cannot be accessed for some unexpected reason. + */ +interface InaccessibleFile { + /** Identifier of the file */ + name: string; + /** Reason for the failure */ + error: unknown; +} + +/** + * Implementation of the check-update hook that finds available SDK updates. + * Prints an object detailing information on Slack dependencies for the CLI. + */ +(async function _(cwd) { + const updates = await checkForSDKUpdates(cwd); + // eslint-disable-next-line no-console + console.log(JSON.stringify(updates)); // stdout +}(process.cwd())); + +/** + * Checks for available SDK updates of specified Slack dependencies. + * @param cwd the current working directory of the CLI project + * @returns a formatted response with dependency information for the CLI + */ +async function checkForSDKUpdates(cwd: string) { + const { versionMap, inaccessibleFiles } = await getProjectDependencies(cwd); + const checkUpdateResponse = createCheckUpdateResponse(versionMap, inaccessibleFiles); + return checkUpdateResponse; +} + +/** + * Gathers version information about Slack packages that are project dependencies. + * @param cwd the current working directory of the CLI project + * @returns a map of version information and any encountered errors + */ +async function getProjectDependencies(cwd: string): Promise<{ + versionMap: Record, + inaccessibleFiles: InaccessibleFile[], +}> { + const { projectDependencies, inaccessibleFiles } = await gatherDependencyFile(cwd); + const versionMap: Record = {}; + try { + if (projectDependencies.dependencies[SLACK_BOLT_SDK]) { + versionMap[SLACK_BOLT_SDK] = await collectVersionInfo(SLACK_BOLT_SDK); + } + if (projectDependencies.dependencies[SLACK_DENO_SDK]) { + versionMap[SLACK_DENO_SDK] = await collectVersionInfo(SLACK_DENO_SDK); + } + if (projectDependencies.dependencies[SLACK_CLI_HOOKS]) { + versionMap[SLACK_CLI_HOOKS] = await collectVersionInfo(SLACK_CLI_HOOKS); + } + } catch (err) { + inaccessibleFiles.push({ name: projectDependencies.fileName, error: err }); + } + return { versionMap, inaccessibleFiles }; +} + +/** + * Gathers dependencies and version information from the project (package.json). + * @param cwd the current working directory of the CLI project + * @returns dependencies found for the project and any encountered errors + */ +async function gatherDependencyFile(cwd: string): Promise<{ + projectDependencies: ProjectDependencies, + inaccessibleFiles: InaccessibleFile[], +}> { + const packageJSONFileName = 'package.json'; + const projectDependencies: ProjectDependencies = { + fileName: packageJSONFileName, + dependencies: {}, + }; + const inaccessibleFiles = []; + try { + const packageJSONFile = await getJSON(`${cwd}/${packageJSONFileName}`); + if ('devDependencies' in packageJSONFile && + typeof packageJSONFile.devDependencies === 'object' && + packageJSONFile.devDependencies !== null && + Object.values(packageJSONFile.devDependencies).every((value) => (typeof value === 'string'))) { + projectDependencies.dependencies = packageJSONFile.devDependencies as Record; + } + if ('dependencies' in packageJSONFile && + typeof packageJSONFile.dependencies === 'object' && + packageJSONFile.dependencies !== null && + Object.values(packageJSONFile.dependencies).every((value) => (typeof value === 'string'))) { + projectDependencies.dependencies = { + ...projectDependencies.dependencies, + ...packageJSONFile.dependencies as Record, + }; + } + } catch (err) { + inaccessibleFiles.push({ name: packageJSONFileName, error: err }); + } + return { projectDependencies, inaccessibleFiles }; +} + +/** + * Finds version information for a package and prepares release information. + * @param packageName name of the package to lookup + * @returns current version and latest release information for the package + */ +async function collectVersionInfo(packageName: string): Promise { + let currentVersion: string | undefined; + let latestVersion: string | undefined; + let releaseNotesUrl: string | undefined; + let dependencyError: ErrorInfo | undefined; + try { + currentVersion = await getProjectPackageVersion(packageName); + latestVersion = await fetchLatestPackageVersion(packageName); + if (hasAvailableUpdates(currentVersion, latestVersion)) { + releaseNotesUrl = getReleaseNotesUrl(packageName, latestVersion); + } + } catch (err: unknown) { + if (typeof err === 'string') { + dependencyError = { message: err }; + } else if (err instanceof Error) { + dependencyError = { message: err.message }; + } + } + return { + name: packageName, + current: currentVersion, + latest: latestVersion, + update: hasAvailableUpdates(currentVersion, latestVersion), + breaking: hasBreakingChange(currentVersion, latestVersion), + message: undefined, + url: releaseNotesUrl, + error: dependencyError, + }; +} + +/** + * Finds the current version of a local project package. + * @param packageName name of the package to lookup + * @returns a stringified semver of the found version + */ +async function getProjectPackageVersion(packageName: string): Promise { + const stdout = await execWrapper(`npm list ${packageName} --depth=0 --json`); + const currentVersionOutput = JSON.parse(stdout); + if (!currentVersionOutput.dependencies || !currentVersionOutput.dependencies[packageName]) { + throw new Error(`Failed to gather project information about ${packageName}`); + } + return currentVersionOutput.dependencies[packageName].version; +} + +/** + * Gets the latest package version. + * @param packageName the package that the latest version is being queried for + * @returns the most recent version of the published package + */ +async function fetchLatestPackageVersion(packageName: string): Promise { + const command = `npm info ${packageName} version --tag latest`; + const stdout = await execWrapper(command); + return stdout; +} + +/** + * Formats the URL with the release notes for a package. + * @param packageName the package with the release + * @param latestVersion the version of the recent release + * @returns a URL with release notes + */ +function getReleaseNotesUrl(packageName: string, latestVersion: string): string | undefined { + if (packageName === SLACK_BOLT_SDK) { + return `https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@${latestVersion}`; + } if (packageName === SLACK_DENO_SDK) { + return `https://github.com/slackapi/deno-slack-sdk/releases/tag/${latestVersion}`; + } if (packageName === SLACK_CLI_HOOKS) { + return `https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/hooks@${latestVersion}`; + } + return undefined; +} + +/** + * Checks if the latest version is more recent than the current version. + * @param current package version available in the project + * @param latest most up-to-date dependency version available on NPM + */ +function hasAvailableUpdates(current: string | undefined, latest: string | undefined): boolean { + if (!current || !latest) { + return false; + } + return current !== latest; +} + +/** + * Checks if updating a dependency to the latest version causes a breaking change. + * @param current package version available in the project + * @param latest most up-to-date dependency version available on NPM + * @returns if the update will result in a breaking change + */ +function hasBreakingChange(current: string | undefined, latest: string | undefined): boolean { + if (!current || !latest) { + return false; + } + return current !== latest; +} + +/** + * Wraps and parses the output of the exec() function + * @param command the command being run by the exec() function + * @returns the output from the command + */ +async function execWrapper(command: string): Promise { + const { stdout } = await exec(command); + return stdout.trim(); +} + +/** + * Reads and parses a JSON file to return the contents + * @param filePath the path of the file being read + * @returns the file contents or a thrown error + */ +async function getJSON(filePath: string): Promise { + if (fs.existsSync(filePath)) { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); + } + throw new Error(`Cannot find a file at path ${filePath}`); +} + +/** + * Creates the check update response in the format expected by the CLI. + * @param versionMap information about package versions and potential updates + * @param inaccessibleFiles array of files that could not be read or accessed + * @returns update information formatted in the expected manner + */ +function createCheckUpdateResponse( + versionMap: Record, + inaccessibleFiles: InaccessibleFile[], +): UpdateInfo { + const dependencyErrors: string[] = []; + const releases = Object.entries(versionMap).map(([dependency, version]) => { + if (version.error) { + dependencyErrors.push(dependency); + } + return version; + }); + return { + name: 'the Slack SDK', + message: '', + releases, + url: 'https://api.slack.com/automation/changelog', + error: createUpdateErrorMessage(dependencyErrors, inaccessibleFiles), + }; +} + +/** + * Prepares a message about any errors encountered. + * @param dependencyErrors array of packages that failed by unexpected reason + * @param inaccessibleFiles array of files that could not be read or accessed + * @returns information about errors in a formatted message + */ +function createUpdateErrorMessage( + dependencyErrors: string[], + inaccessibleFiles: InaccessibleFile[], +): ErrorInfo | undefined { + if (dependencyErrors.length === 0 && inaccessibleFiles.length === 0) { + return undefined; + } + let message: string = ''; + if (dependencyErrors.length > 0) { + message = `An error occurred fetching updates for the following packages: ${dependencyErrors.join(', ')}\n`; + } + const fileErrors = inaccessibleFiles.map((file) => `\n ${file.name}: ${file.error}`); + if (dependencyErrors.length > 0) { + message += `An error occurred while reading the following files:\n${fileErrors.join('')}`; + } + return { message }; +} diff --git a/packages/hooks/src/get-hooks.js b/packages/hooks/src/get-hooks.js deleted file mode 100755 index d8668e18d..000000000 --- a/packages/hooks/src/get-hooks.js +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node -console.log(JSON.stringify({ - hooks: { - 'get-manifest': 'npx -q --no-install -p @slack/bolt slack-cli-get-manifest', - 'check-update': 'npx -q --no-install -p @slack/bolt slack-cli-check-update', - start: 'npx -q --no-install -p @slack/bolt slack-cli-start', - }, - config: { - watch: { - 'filter-regex': '^manifest\\.(ts|js|json)$', - paths: [ - '.', - ], - }, - 'sdk-managed-connection-enabled': true, - }, -})); \ No newline at end of file diff --git a/packages/hooks/src/get-hooks.ts b/packages/hooks/src/get-hooks.ts new file mode 100755 index 000000000..ae0628e20 --- /dev/null +++ b/packages/hooks/src/get-hooks.ts @@ -0,0 +1,19 @@ +#!/usr/bin/env node +/* eslint-disable @typescript-eslint/naming-convention */ +// eslint-disable-next-line no-console +console.log(JSON.stringify({ + hooks: { + 'get-manifest': 'npx -q --no-install -p @slack/hooks slack-cli-get-manifest', + 'check-update': 'npx -q --no-install -p @slack/hooks slack-cli-check-update', + start: 'npx -q --no-install -p @slack/hooks slack-cli-start', + }, + config: { + watch: { + 'filter-regex': '^manifest\\.(ts|js|json)$', + paths: [ + '.', + ], + }, + 'sdk-managed-connection-enabled': true, + }, +})); diff --git a/packages/hooks/src/get-manifest.js b/packages/hooks/src/get-manifest.ts similarity index 61% rename from packages/hooks/src/get-manifest.js rename to packages/hooks/src/get-manifest.ts index 303ba8afc..43d450432 100755 --- a/packages/hooks/src/get-manifest.js +++ b/packages/hooks/src/get-manifest.ts @@ -1,80 +1,78 @@ #!/usr/bin/env node -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path from 'path'; -/** +/** * Implements the get-manifest script hook required by the Slack CLI * Returns a manifest JSON string to stdout. -*/ -(function _(cwd) { - let manifest = getManifestData(cwd); - console.log(JSON.stringify(manifest)); + */ +(function _(cwd: string) { + const manifest = getManifestData(cwd); + console.log(JSON.stringify(manifest)); // eslint-disable-line no-console }(process.cwd())); -/** +/** * Returns manifest data * @param searchDir path to begin searching at */ -function getManifestData(searchDir) { +function getManifestData(searchDir: string): object { const manifestJSON = readManifestJSONFile(searchDir, 'manifest.json'); if (!manifestJSON) { - const msg = 'Unable to find a manifest file in this project'; + const msg = 'Failed to find a manifest file in this project'; throw new Error(msg); } return manifestJSON; -} +} -/** +/** * Returns a manifest.json if it exists, null otherwise * @param searchDir typically current working directory * @param filename file to search for */ -function readManifestJSONFile(searchDir, filename) { - let jsonFilePath, manifestJSON; - +function readManifestJSONFile(searchDir: string, filename: string): object | null { + let jsonFilePath; + let manifestJSON; + try { jsonFilePath = find(searchDir, filename); - if (fs.existsSync(jsonFilePath)) { + if (jsonFilePath && fs.existsSync(jsonFilePath)) { manifestJSON = JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); } } catch (error) { - console.error(error) + console.error(error); // eslint-disable-line no-console return null; } - + return manifestJSON; } -/** - * Search for provided file path. - * Returns full path when filename is found or null if no file found. +/** + * Search for provided file path. + * Returns full path when filename is found or null if no file found. * @param currentPath string of current path * @param targetFilename filename to match * @returns full file path string relative to starting path or null - * */ -function find(currentPath, targetFilename) { + */ +function find(currentPath: string, targetFilename: string): string | undefined { // TODO Cache searched paths and check that they haven't been explored already - // This guards against rare edge case of a subdir in the file tree which is + // This guards against rare edge case of a subdir in the file tree which is // symlinked back to root or in such a way that creates a cycle. Can also implement - // max depth check. + // max depth check. if (currentPath.endsWith(`/${targetFilename}`)) { return currentPath; } if (fs.existsSync(currentPath) && fs.lstatSync(currentPath).isDirectory()) { - let foundEntry; const dirents = fs.readdirSync(currentPath); - for (const entry of dirents) { + return dirents.find((entry) => { if (entry !== 'node_modules') { - let newPath = path.resolve(currentPath, entry); - foundEntry = find(newPath, targetFilename); - if (foundEntry) { - return foundEntry; - } + const newPath = path.resolve(currentPath, entry); + return find(newPath, targetFilename); } - } - return null; + return false; + }); } -} \ No newline at end of file + return undefined; +} diff --git a/packages/hooks/src/start.js b/packages/hooks/src/start.ts similarity index 71% rename from packages/hooks/src/start.js rename to packages/hooks/src/start.ts index c3d1bfbe5..bf8f0194a 100755 --- a/packages/hooks/src/start.js +++ b/packages/hooks/src/start.ts @@ -1,22 +1,23 @@ #!/usr/bin/env node -const { spawn } = require('child_process'); -const path = require('path'); -const fs = require('fs'); +import { spawn } from 'child_process'; +import path from 'path'; +import fs from 'fs'; + const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf-8')); // Run script hook verifies that requirements for running an App in // in developerMode (via Socket Mode) are met -(function _(cwd, customPath) { +(function _(cwd, customPath): void { // TODO - Format so that its less miss-able in output - console.log('Preparing local run in developer mode (Socket Mode)'); + console.log('Preparing local run in developer mode (Socket Mode)'); // eslint-disable-line no-console // Check required local run tokens validate(); - // tries the provided path, then package.json main, then defaults to index.js in the current + // tries the provided path, then package.json main, then defaults to index.js in the current // working directory const pkgJSONDefault = 'index.js'; - const fullPath = path.resolve(cwd, customPath ? customPath : pkgJSONMain ? pkgJSONMain : pkgJSONDefault); - console.log(fullPath); + const fullPath = path.resolve(cwd, customPath || (pkgJSONMain || pkgJSONDefault)); + console.log(fullPath); // eslint-disable-line no-console // Kick off a subprocess to run the app in development mode const app = spawn('node', [`${fullPath}`]); @@ -29,15 +30,15 @@ const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf- }); app.on('close', (code) => { - console.log(`bolt-app local run exited with code ${code}`); + console.log(`bolt-app local run exited with code ${code}`); // eslint-disable-line no-console }); }(process.cwd(), process.env.SLACK_CLI_CUSTOM_FILE_PATH)); -function validate() { +function validate(): void { if (!process.env.SLACK_CLI_XOXB) { throw new Error('Missing local run bot token. Please see slack-cli maintainers to troubleshoot.'); } if (!process.env.SLACK_CLI_XAPP) { throw new Error('Missing local run app token. Please see slack-cli maintainers to troubleshoot'); } -} \ No newline at end of file +} diff --git a/packages/hooks/tsconfig.eslint.json b/packages/hooks/tsconfig.eslint.json new file mode 120000 index 000000000..2cd9fb812 --- /dev/null +++ b/packages/hooks/tsconfig.eslint.json @@ -0,0 +1 @@ +../../lint-configs/tsconfig.eslint.json \ No newline at end of file diff --git a/packages/hooks/tsconfig.json b/packages/hooks/tsconfig.json new file mode 100644 index 000000000..5553acc9e --- /dev/null +++ b/packages/hooks/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + + "moduleResolution": "node", + "baseUrl": ".", + "paths": { + "*": ["./types/*"] + }, + "esModuleInterop" : true, + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "src/**/*.spec.js", + "src/**/*.js" + ], + "jsdoc": { + "out": "support/jsdoc", + "access": "public" + } +} + From 808fba4b1ce4d82fa26c7a2a43bb1c05712fcec0 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Mon, 8 Jan 2024 21:04:47 -0800 Subject: [PATCH 04/45] chore: bump package version after accidental publish --- packages/hooks/package-lock.json | 4 ++-- packages/hooks/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json index a445d5a2f..ce770bf62 100644 --- a/packages/hooks/package-lock.json +++ b/packages/hooks/package-lock.json @@ -1,12 +1,12 @@ { "name": "@slack/hooks", - "version": "0.0.2", + "version": "0.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@slack/hooks", - "version": "0.0.2", + "version": "0.0.3", "license": "MIT", "bin": { "slack-cli-check-update": "dist/check-update.js", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 5e0e8759f..eebfff529 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/hooks", - "version": "0.0.2", + "version": "0.0.3", "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From 8a889eb92399685fbc1163dce95b475745318c03 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Tue, 9 Jan 2024 17:45:19 -0800 Subject: [PATCH 05/45] feat: remove a build step but keep typings with jsdoc --- lint-configs/.eslintrc.js | 3 - packages/hooks/.eslintrc.cjs | 176 ++++++ packages/hooks/.eslintrc.js | 1 - packages/hooks/.gitignore | 3 - .../hooks/{tsconfig.json => jsconfig.json} | 5 +- packages/hooks/package-lock.json | 521 +----------------- packages/hooks/package.json | 27 +- .../src/{check-update.ts => check-update.js} | 227 ++++---- .../hooks/src/{get-hooks.ts => get-hooks.js} | 1 - packages/hooks/src/get-manifest.js | 73 +++ packages/hooks/src/get-manifest.ts | 78 --- packages/hooks/src/{start.ts => start.js} | 17 +- packages/hooks/tsconfig.eslint.json | 1 - 13 files changed, 409 insertions(+), 724 deletions(-) create mode 100644 packages/hooks/.eslintrc.cjs delete mode 120000 packages/hooks/.eslintrc.js rename packages/hooks/{tsconfig.json => jsconfig.json} (90%) rename packages/hooks/src/{check-update.ts => check-update.js} (52%) rename packages/hooks/src/{get-hooks.ts => get-hooks.js} (89%) create mode 100755 packages/hooks/src/get-manifest.js delete mode 100755 packages/hooks/src/get-manifest.ts rename packages/hooks/src/{start.ts => start.js} (78%) delete mode 120000 packages/hooks/tsconfig.eslint.json diff --git a/lint-configs/.eslintrc.js b/lint-configs/.eslintrc.js index 081a6591f..a1ebd902c 100644 --- a/lint-configs/.eslintrc.js +++ b/lint-configs/.eslintrc.js @@ -65,9 +65,6 @@ module.exports = { // Allow safe references to functions before the declaration. Overrides AirBnB config. Not located in the override // section below because a distinct override is necessary in TypeScript files. 'no-use-before-define': ['error', 'nofunc'], - - // Allow scripts for hooks implementations. - 'node/shebang': 'off', }, overrides: [ diff --git a/packages/hooks/.eslintrc.cjs b/packages/hooks/.eslintrc.cjs new file mode 100644 index 000000000..ceeb67611 --- /dev/null +++ b/packages/hooks/.eslintrc.cjs @@ -0,0 +1,176 @@ +// SlackAPI JavaScript style +// --- +// This style helps maintainers enforce safe and consistent programming practices in this project. It is not meant to be +// comprehensive on its own or vastly different from existing styles. The goal is to inherit and aggregate as many of +// the communities' recommended styles for the technologies used as we can. When, and only when, we have a stated need +// to differentiate, we add more rules (or modify options). Therefore, the fewer rules directly defined in this file, +// the better. +// +// These styles are a subset of the shared JavaScript and TypeScript configurations to only target JavaScript packages. + +module.exports = { + // This is a root of the project, ESLint should not look through parent directories to find more config + root: true, + + ignorePatterns: [ + // Ignore all build outputs and artifacts (node_modules, dotfiles, and dot directories are implicitly ignored) + '/coverage', + ], + + // These environments contain lists of global variables which are allowed to be accessed + env: { + // The target node version (v18) supports all important ES2021 features: https://node.green + es2021: true, + node: true, + }, + + extends: [ + // ESLint's recommended built-in rules: https://eslint.org/docs/rules/ + 'eslint:recommended', + + // Node plugin's recommended rules: https://github.com/mysticatea/eslint-plugin-node + 'plugin:node/recommended', + + // AirBnB style guide (without React) rules: https://github.com/airbnb/javascript. + 'airbnb-base', + + // JSDoc plugin's recommended rules + 'plugin:jsdoc/recommended', + ], + + rules: { + // JavaScript rules + // --- + // The top level of this configuration contains rules which apply to JavaScript. + // + // This section does not contain rules meant to override options or disable rules in the base configurations + // (ESLint, Node, AirBnb). Those rules are added in the final override. + + // Eliminate tabs to standardize on spaces for indentation. If you want to use tabs for something other than + // indentation, you may need to turn this rule off using an inline config comments. + 'no-tabs': 'error', + + // Bans use of comma as an operator because it can obscure side effects and is often an accident. + 'no-sequences': 'error', + + // Disallow the use of process.exit() + 'node/no-process-exit': 'error', + + // Allow safe references to functions before the declaration. + 'no-use-before-define': ['error', 'nofunc'], + + // Allow scripts for hooks implementations. + 'node/shebang': 'off', + + // Allow unlimited classes in a file. + 'max-classes-per-file': 'off', + + // Disallow invocations of require(). This will help make imports more consistent and ensures a smoother + // transition to the best future syntax. + 'import/no-commonjs': ['error', { + allowConditionalRequire: false, + }], + + // Don't verify that all named imports are part of the set of named exports for the referenced module. The + // TypeScript compiler will already perform this check, so it is redundant. + 'import/named': 'off', + 'node/no-missing-import': 'off', + + // Allow use of import and export syntax, despite it not being supported in the node versions. Since this + // project is transpiled, the ignore option is used. Overrides node/recommended. + 'node/no-unsupported-features/es-syntax': ['error', { ignores: ['modules'] }], + + 'operator-linebreak': ['error', 'after', { + overrides: { '=': 'none' } + }], + }, + + overrides: [ + { + files: ['**/*.js'], + rules: { + // Override rules + // --- + // This level of this configuration contains rules which override options or disable rules in the base + // configurations in JavaScript. + + // Increase the max line length to 120. The rest of this setting is copied from the AirBnB config. + 'max-len': ['error', 120, 2, { + ignoreUrls: true, + ignoreComments: false, + ignoreRegExpLiterals: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + }], + + // Restrict the use of backticks to declare a normal string. Template literals should only be used when the + // template string contains placeholders. The rest of this setting is copied from the AirBnb config. + quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }], + + // The server side Slack API uses snake_case for parameters often. + // + // For mocking and override support, we need to allow snake_case. + // Allow leading underscores for parameter names, which is used to acknowledge unused variables in TypeScript. + // Also, enforce camelCase naming for variables. Ideally, the leading underscore could be restricted to only + // unused parameter names, but this rule isn't capable of knowing when a variable is unused. The camelcase and + // no-underscore-dangle rules are replaced with the naming-convention rule because this single rule can serve + // both purposes, and it works fine on non-TypeScript code. + camelcase: 'error', + 'no-underscore-dangle': 'error', + 'no-unused-vars': [ + 'error', + { + varsIgnorePattern: '^_', + argsIgnorePattern: '^_' + } + ], + + // Allow cyclical imports. Turning this rule on is mainly a way to manage the performance concern for linting + // time. Our projects are not large enough to warrant this. Overrides AirBnB styles. + 'import/no-cycle': 'off', + + // Prevent importing submodules of other modules. Using the internal structure of a module exposes + // implementation details that can potentially change in breaking ways. Overrides AirBnB styles. + 'import/no-internal-modules': ['error', { + // Use the following option to set a list of allowable globs in this project. + allow: [ + '**/middleware/*', // the src/middleware directory doesn't export a module, it's just a namespace. + '**/receivers/*', // the src/receivers directory doesn't export a module, it's just a namespace. + '**/types/**/*', + '**/types/*', // type heirarchies should be used however one wants + ], + }], + + // Remove the minProperties option for enforcing line breaks between braces. The AirBnB config sets this to 4, + // which is arbitrary and not backed by anything specific in the style guide. If we just remove it, we can + // rely on the max-len rule to determine if the line is too long and then enforce line breaks. Overrides AirBnB + // styles. + 'object-curly-newline': ['error', { multiline: true, consistent: true }], + }, + }, + { + files: ['src/**/*.spec.js'], + rules: { + // Test-specific rules + // --- + // Rules that only apply to JavaScript _test_ source files + + // With Mocha as a test framework, it is sometimes helpful to assign + // shared state to Mocha's Context object, for example in setup and + // teardown test methods. Assigning stub/mock objects to the Context + // object via `this` is a common pattern in Mocha. As such, using + // `function` over the the arrow notation binds `this` appropriately and + // should be used in tests. So: we turn off the prefer-arrow-callback + // rule. + // See https://github.com/slackapi/bolt-js/pull/1012#pullrequestreview-711232738 + // for a case of arrow-vs-function syntax coming up for the team + 'prefer-arrow-callback': 'off', + // Using ununamed functions (e.g., null logger) in tests is fine + 'func-names': 'off', + // In tests, don't force constructing a Symbol with a descriptor, as + // it's probably just for tests + 'symbol-description': 'off', + }, + }, + ], +}; diff --git a/packages/hooks/.eslintrc.js b/packages/hooks/.eslintrc.js deleted file mode 120000 index 5962fa3ca..000000000 --- a/packages/hooks/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -../../lint-configs/.eslintrc.js \ No newline at end of file diff --git a/packages/hooks/.gitignore b/packages/hooks/.gitignore index 33ce574cc..48344fccd 100644 --- a/packages/hooks/.gitignore +++ b/packages/hooks/.gitignore @@ -1,6 +1,3 @@ # node / npm stuff /node_modules package-lock.json - -# build products -/dist diff --git a/packages/hooks/tsconfig.json b/packages/hooks/jsconfig.json similarity index 90% rename from packages/hooks/tsconfig.json rename to packages/hooks/jsconfig.json index 5553acc9e..fa4d6451e 100644 --- a/packages/hooks/tsconfig.json +++ b/packages/hooks/jsconfig.json @@ -6,6 +6,7 @@ "declarationMap": true, "sourceMap": true, "outDir": "dist", + "checkJs": true, "strict": true, "noUnusedLocals": true, @@ -23,10 +24,6 @@ "include": [ "src/**/*" ], - "exclude": [ - "src/**/*.spec.js", - "src/**/*.js" - ], "jsdoc": { "out": "support/jsdoc", "access": "public" diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json index ce770bf62..c60e692a0 100644 --- a/packages/hooks/package-lock.json +++ b/packages/hooks/package-lock.json @@ -1,24 +1,22 @@ { "name": "@slack/hooks", - "version": "0.0.3", + "version": "0.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@slack/hooks", - "version": "0.0.3", + "version": "0.0.4", "license": "MIT", "bin": { - "slack-cli-check-update": "dist/check-update.js", - "slack-cli-get-hooks": "dist/get-hooks.js", - "slack-cli-get-manifest": "dist/get-manifest.js", - "slack-cli-start": "dist/start.js" + "slack-cli-check-update": "src/check-update.js", + "slack-cli-get-hooks": "src/get-hooks.js", + "slack-cli-get-manifest": "src/get-manifest.js", + "slack-cli-start": "src/start.js" }, "devDependencies": { - "@types/node": "^20.10.6", - "@typescript-eslint/eslint-plugin": "^6.17.0", + "@types/node": "^20.10.8", "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "^17.1.0", "eslint-plugin-jsdoc": "^48.0.2", "eslint-plugin-node": "^11.1.0", "shx": "^0.3.4" @@ -57,6 +55,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "peer": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -72,6 +71,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, + "peer": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -151,6 +151,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "peer": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -164,6 +165,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "peer": true, "engines": { "node": ">= 8" } @@ -173,6 +175,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "peer": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -181,12 +184,6 @@ "node": ">= 8" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -195,280 +192,14 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.10.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", - "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "version": "20.10.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz", + "integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, - "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", - "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/type-utils": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", - "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", - "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", - "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "6.17.0", - "@typescript-eslint/utils": "6.17.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", - "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", - "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/visitor-keys": "6.17.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", - "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.17.0", - "@typescript-eslint/types": "6.17.0", - "@typescript-eslint/typescript-estree": "6.17.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", - "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.17.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -591,15 +322,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.findlastindex": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", @@ -707,18 +429,6 @@ "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/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -883,18 +593,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1089,21 +787,6 @@ "eslint-plugin-import": "^2.25.2" } }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", - "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" - } - }, "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", @@ -1332,6 +1015,7 @@ "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, + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1408,34 +1092,6 @@ "dev": true, "peer": true }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/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/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", @@ -1455,6 +1111,7 @@ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, + "peer": true, "dependencies": { "reusify": "^1.0.4" } @@ -1472,18 +1129,6 @@ "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", @@ -1669,26 +1314,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -1705,7 +1330,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "peer": true }, "node_modules/has-bigints": { "version": "1.0.2", @@ -1965,6 +1591,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -1974,6 +1601,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "peer": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1993,15 +1621,6 @@ "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", @@ -2240,28 +1859,6 @@ "node": ">=10" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2293,7 +1890,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/object-inspect": { "version": "1.13.1", @@ -2501,27 +2099,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2560,7 +2137,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "peer": true }, "node_modules/rechoir": { "version": "0.6.2", @@ -2635,6 +2213,7 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "peer": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -2675,6 +2254,7 @@ "url": "https://feross.org/support" } ], + "peer": true, "dependencies": { "queue-microtask": "^1.2.2" } @@ -2819,15 +2399,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -2963,30 +2534,6 @@ "dev": true, "peer": true }, - "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": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -3091,20 +2638,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index eebfff529..a9565a63f 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/hooks", - "version": "0.0.3", + "version": "0.0.4", "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", @@ -9,9 +9,10 @@ "cli", "hooks" ], - "main": "dist/get-hooks.js", + "type": "module", + "main": "src/get-hooks.js", "files": [ - "dist/*.js" + "src/*.js" ], "engines": { "node": ">= 18", @@ -29,24 +30,20 @@ "url": "https://github.com/slackapi/node-slack-sdk/issues" }, "scripts": { - "clean": "shx rm -rf ./dist", - "prebuild": "npm run clean", - "build": "tsc", - "postbuild": "shx chmod +x dist/*.js", - "lint": "eslint --ext .ts src", + "build": "shx chmod +x src/*.js", + "prelint": "tsc --noemit --project ./jsconfig.json", + "lint": "eslint --ext .js src", "test": "echo \"Tests are not implemented.\" && exit 0" }, "bin": { - "slack-cli-get-hooks": "dist/get-hooks.js", - "slack-cli-get-manifest": "dist/get-manifest.js", - "slack-cli-check-update": "dist/check-update.js", - "slack-cli-start": "dist/start.js" + "slack-cli-get-hooks": "src/get-hooks.js", + "slack-cli-get-manifest": "src/get-manifest.js", + "slack-cli-check-update": "src/check-update.js", + "slack-cli-start": "src/start.js" }, "devDependencies": { - "@types/node": "^20.10.6", - "@typescript-eslint/eslint-plugin": "^6.17.0", + "@types/node": "^20.10.8", "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "^17.1.0", "eslint-plugin-jsdoc": "^48.0.2", "eslint-plugin-node": "^11.1.0", "shx": "^0.3.4" diff --git a/packages/hooks/src/check-update.ts b/packages/hooks/src/check-update.js similarity index 52% rename from packages/hooks/src/check-update.ts rename to packages/hooks/src/check-update.js index 41cd8bfe2..ebe037500 100755 --- a/packages/hooks/src/check-update.ts +++ b/packages/hooks/src/check-update.js @@ -6,68 +6,46 @@ import childProcess from 'child_process'; const exec = util.promisify(childProcess.exec); const SLACK_BOLT_SDK = '@slack/bolt'; -const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; const SLACK_CLI_HOOKS = '@slack/hooks'; +const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; -interface UpdateInfo { - /** Overall package identifier */ - name: string; - /** Collection of new releases */ - releases: ReleaseInfo[]; - /** Details about any updates */ - message: string | undefined; - /** Additional notes to inspect */ - url: string | undefined; - /** Information of happened failures */ - error: ErrorInfo | undefined; -} - -interface ReleaseInfo { - /** Dependency identifier on known registry. */ - name: string; - /** Version present in the current project. */ - current: string | undefined; - /** Most recent version available to download. */ - latest: string | undefined; - /** If latest version is newer than current. */ - update: boolean; - /** If latest version requires a major bump. */ - breaking: boolean; - /** Additional information for the dependency. */ - message: string | undefined; - /** Web address containing update information. */ - url: string | undefined; - /** Information of failures found gathering. */ - error: ErrorInfo | undefined; -} +/** + * @typedef {object} UpdateInfo + * @property {string} name - Overall identifier of the package. + * @property {ReleaseInfo[]} releases - Collection of new releases. + * @property {string | undefined} message - Details about updates. + * @property {string | undefined} url - More information to inspect. + * @property {ErrorInfo | undefined} error - Notes of any failures. + */ -interface ErrorInfo { - message: string; -} +/** + * @typedef {object} ReleaseInfo + * @property {string} name - Dependency identifier on registry. + * @property {string | undefined} current - Version in current project. + * @property {string | undefined} latest - Most recent version available. + * @property {boolean} update - If latest version is newer than current. + * @property {boolean} breaking - If latest version requires a major bump. + * @property {string | undefined} message - Details about the dependency. + * @property {string | undefined} url - More information to inspect. + * @property {ErrorInfo | undefined} error - Notes of any failures. + */ /** - * Mappings from dependencies to installed packages for the project. + * @typedef {object} ErrorInfo + * @property {string} message - Details about the error. */ -interface ProjectDependencies { - /** The file contianing package information. Often package.json. */ - fileName: string; - /** Pairs of packages and the matching values in a package.json. */ - dependencies: Record; -} /** * File that cannot be accessed for some unexpected reason. + * @typedef {object} InaccessibleFile + * @property {string} name - Identifier of the file. + * @property {unknown} error - Cause of the failure. */ -interface InaccessibleFile { - /** Identifier of the file */ - name: string; - /** Reason for the failure */ - error: unknown; -} /** * Implementation of the check-update hook that finds available SDK updates. * Prints an object detailing information on Slack dependencies for the CLI. + * @param {string} cwd - The current working directory of the project. */ (async function _(cwd) { const updates = await checkForSDKUpdates(cwd); @@ -77,26 +55,31 @@ interface InaccessibleFile { /** * Checks for available SDK updates of specified Slack dependencies. - * @param cwd the current working directory of the CLI project - * @returns a formatted response with dependency information for the CLI + * @param {string} cwd - The current working directory of the CLI project. + * @returns {Promise} Formatted package version information. */ -async function checkForSDKUpdates(cwd: string) { +async function checkForSDKUpdates(cwd) { const { versionMap, inaccessibleFiles } = await getProjectDependencies(cwd); const checkUpdateResponse = createCheckUpdateResponse(versionMap, inaccessibleFiles); return checkUpdateResponse; } +/** + * @typedef ProjectDependencies + * @property {Record} versionMap - + * @property {InaccessibleFile[]} inaccessibleFiles - + * Array of files that could not be read or accessed. + */ + /** * Gathers version information about Slack packages that are project dependencies. - * @param cwd the current working directory of the CLI project - * @returns a map of version information and any encountered errors + * @param {string} cwd - The current working directory of the CLI project. + * @returns {Promise} a map of version information and any encountered errors */ -async function getProjectDependencies(cwd: string): Promise<{ - versionMap: Record, - inaccessibleFiles: InaccessibleFile[], -}> { +async function getProjectDependencies(cwd) { + /** @type {Record} */ + const versionMap = {}; const { projectDependencies, inaccessibleFiles } = await gatherDependencyFile(cwd); - const versionMap: Record = {}; try { if (projectDependencies.dependencies[SLACK_BOLT_SDK]) { versionMap[SLACK_BOLT_SDK] = await collectVersionInfo(SLACK_BOLT_SDK); @@ -113,17 +96,28 @@ async function getProjectDependencies(cwd: string): Promise<{ return { versionMap, inaccessibleFiles }; } +/** + * Details about the dependencies and versioning for the current project. + * @typedef DependencyFile + * @property {ProjectPackages} projectDependencies - Installation information of packages. + * @property {InaccessibleFile[]} inaccessibleFiles - Array of files that could not be read. + */ + +/** + * Mappings from dependencies to installed package information for the project. + * @typedef {object} ProjectPackages + * @property {string} fileName - The file with package information (package.json). + * @property {Record} dependencies - Install details for packages. + */ + /** * Gathers dependencies and version information from the project (package.json). - * @param cwd the current working directory of the CLI project - * @returns dependencies found for the project and any encountered errors + * @param {string} cwd - The current working directory of the CLI project. + * @returns {Promise} Dependencies found for the project and any encountered errors. */ -async function gatherDependencyFile(cwd: string): Promise<{ - projectDependencies: ProjectDependencies, - inaccessibleFiles: InaccessibleFile[], -}> { +async function gatherDependencyFile(cwd) { const packageJSONFileName = 'package.json'; - const projectDependencies: ProjectDependencies = { + const projectDependencies = { fileName: packageJSONFileName, dependencies: {}, }; @@ -134,16 +128,13 @@ async function gatherDependencyFile(cwd: string): Promise<{ typeof packageJSONFile.devDependencies === 'object' && packageJSONFile.devDependencies !== null && Object.values(packageJSONFile.devDependencies).every((value) => (typeof value === 'string'))) { - projectDependencies.dependencies = packageJSONFile.devDependencies as Record; + Object.assign(projectDependencies.dependencies, packageJSONFile.devDependencies); } if ('dependencies' in packageJSONFile && typeof packageJSONFile.dependencies === 'object' && packageJSONFile.dependencies !== null && Object.values(packageJSONFile.dependencies).every((value) => (typeof value === 'string'))) { - projectDependencies.dependencies = { - ...projectDependencies.dependencies, - ...packageJSONFile.dependencies as Record, - }; + Object.assign(projectDependencies.dependencies, packageJSONFile.dependencies); } } catch (err) { inaccessibleFiles.push({ name: packageJSONFileName, error: err }); @@ -153,21 +144,25 @@ async function gatherDependencyFile(cwd: string): Promise<{ /** * Finds version information for a package and prepares release information. - * @param packageName name of the package to lookup - * @returns current version and latest release information for the package + * @param {string} packageName - Name of the package to lookup. + * @returns {Promise} Current version and release information for the package. */ -async function collectVersionInfo(packageName: string): Promise { - let currentVersion: string | undefined; - let latestVersion: string | undefined; - let releaseNotesUrl: string | undefined; - let dependencyError: ErrorInfo | undefined; +async function collectVersionInfo(packageName) { + /** @type {string | undefined} */ + let currentVersion; + /** @type {string | undefined} */ + let latestVersion; + /** @type {string | undefined} */ + let releaseNotesUrl; + /** @type {ErrorInfo | undefined} */ + let dependencyError; try { currentVersion = await getProjectPackageVersion(packageName); latestVersion = await fetchLatestPackageVersion(packageName); if (hasAvailableUpdates(currentVersion, latestVersion)) { releaseNotesUrl = getReleaseNotesUrl(packageName, latestVersion); } - } catch (err: unknown) { + } catch (err) { if (typeof err === 'string') { dependencyError = { message: err }; } else if (err instanceof Error) { @@ -188,10 +183,10 @@ async function collectVersionInfo(packageName: string): Promise { /** * Finds the current version of a local project package. - * @param packageName name of the package to lookup - * @returns a stringified semver of the found version + * @param {string} packageName - Name of the package to lookup. + * @returns {Promise} A stringified semver of the found version. */ -async function getProjectPackageVersion(packageName: string): Promise { +async function getProjectPackageVersion(packageName) { const stdout = await execWrapper(`npm list ${packageName} --depth=0 --json`); const currentVersionOutput = JSON.parse(stdout); if (!currentVersionOutput.dependencies || !currentVersionOutput.dependencies[packageName]) { @@ -202,10 +197,10 @@ async function getProjectPackageVersion(packageName: string): Promise { /** * Gets the latest package version. - * @param packageName the package that the latest version is being queried for - * @returns the most recent version of the published package + * @param {string} packageName - Package to search for the latest version of. + * @returns {Promise} The most recent version of the published package. */ -async function fetchLatestPackageVersion(packageName: string): Promise { +async function fetchLatestPackageVersion(packageName) { const command = `npm info ${packageName} version --tag latest`; const stdout = await execWrapper(command); return stdout; @@ -213,11 +208,11 @@ async function fetchLatestPackageVersion(packageName: string): Promise { /** * Formats the URL with the release notes for a package. - * @param packageName the package with the release - * @param latestVersion the version of the recent release - * @returns a URL with release notes + * @param {string} packageName - The package with the release. + * @param {string} latestVersion - Recent release version. + * @returns {string | undefined} A URL with release notes. */ -function getReleaseNotesUrl(packageName: string, latestVersion: string): string | undefined { +function getReleaseNotesUrl(packageName, latestVersion) { if (packageName === SLACK_BOLT_SDK) { return `https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@${latestVersion}`; } if (packageName === SLACK_DENO_SDK) { @@ -230,10 +225,11 @@ function getReleaseNotesUrl(packageName: string, latestVersion: string): string /** * Checks if the latest version is more recent than the current version. - * @param current package version available in the project - * @param latest most up-to-date dependency version available on NPM + * @param {string | undefined} current - Package version available in the project. + * @param {string | undefined} latest - Most up-to-date dependency version available. + * @returns {boolean} If the update will result in a breaking change. */ -function hasAvailableUpdates(current: string | undefined, latest: string | undefined): boolean { +function hasAvailableUpdates(current, latest) { if (!current || !latest) { return false; } @@ -242,11 +238,11 @@ function hasAvailableUpdates(current: string | undefined, latest: string | undef /** * Checks if updating a dependency to the latest version causes a breaking change. - * @param current package version available in the project - * @param latest most up-to-date dependency version available on NPM - * @returns if the update will result in a breaking change + * @param {string | undefined} current - Package version available in the project. + * @param {string | undefined} latest - Most up-to-date dependency version available. + * @returns {boolean} If the update will result in a breaking change. */ -function hasBreakingChange(current: string | undefined, latest: string | undefined): boolean { +function hasBreakingChange(current, latest) { if (!current || !latest) { return false; } @@ -255,20 +251,20 @@ function hasBreakingChange(current: string | undefined, latest: string | undefin /** * Wraps and parses the output of the exec() function - * @param command the command being run by the exec() function - * @returns the output from the command + * @param {string} command - The command to soon be executed. + * @returns {Promise} the output from the command. */ -async function execWrapper(command: string): Promise { +async function execWrapper(command) { const { stdout } = await exec(command); return stdout.trim(); } /** - * Reads and parses a JSON file to return the contents - * @param filePath the path of the file being read - * @returns the file contents or a thrown error + * Reads and parses a JSON file to return the contents. + * @param {string} filePath - The path of the file being read. + * @returns {Promise} - The parsed file contents. */ -async function getJSON(filePath: string): Promise { +async function getJSON(filePath) { if (fs.existsSync(filePath)) { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } @@ -277,15 +273,13 @@ async function getJSON(filePath: string): Promise { /** * Creates the check update response in the format expected by the CLI. - * @param versionMap information about package versions and potential updates - * @param inaccessibleFiles array of files that could not be read or accessed - * @returns update information formatted in the expected manner + * @param {Record} versionMap - Information about packages and updates. + * @param {InaccessibleFile[]} inaccessibleFiles - Array of files that could not be read. + * @returns {UpdateInfo} Update information formatted in the expected manner. */ -function createCheckUpdateResponse( - versionMap: Record, - inaccessibleFiles: InaccessibleFile[], -): UpdateInfo { - const dependencyErrors: string[] = []; +function createCheckUpdateResponse(versionMap, inaccessibleFiles) { + /** @type {string[]} */ + const dependencyErrors = []; const releases = Object.entries(versionMap).map(([dependency, version]) => { if (version.error) { dependencyErrors.push(dependency); @@ -303,18 +297,15 @@ function createCheckUpdateResponse( /** * Prepares a message about any errors encountered. - * @param dependencyErrors array of packages that failed by unexpected reason - * @param inaccessibleFiles array of files that could not be read or accessed - * @returns information about errors in a formatted message + * @param {string[]} dependencyErrors - Packages that failed for some unexpected reason. + * @param {InaccessibleFile[]} inaccessibleFiles - Array of files that could not be read. + * @returns {ErrorInfo | undefined} Formatted information about errors. */ -function createUpdateErrorMessage( - dependencyErrors: string[], - inaccessibleFiles: InaccessibleFile[], -): ErrorInfo | undefined { +function createUpdateErrorMessage(dependencyErrors, inaccessibleFiles) { if (dependencyErrors.length === 0 && inaccessibleFiles.length === 0) { return undefined; } - let message: string = ''; + let message = ''; if (dependencyErrors.length > 0) { message = `An error occurred fetching updates for the following packages: ${dependencyErrors.join(', ')}\n`; } diff --git a/packages/hooks/src/get-hooks.ts b/packages/hooks/src/get-hooks.js similarity index 89% rename from packages/hooks/src/get-hooks.ts rename to packages/hooks/src/get-hooks.js index ae0628e20..3f967d5a1 100755 --- a/packages/hooks/src/get-hooks.ts +++ b/packages/hooks/src/get-hooks.js @@ -1,5 +1,4 @@ #!/usr/bin/env node -/* eslint-disable @typescript-eslint/naming-convention */ // eslint-disable-next-line no-console console.log(JSON.stringify({ hooks: { diff --git a/packages/hooks/src/get-manifest.js b/packages/hooks/src/get-manifest.js new file mode 100755 index 000000000..65d69aea1 --- /dev/null +++ b/packages/hooks/src/get-manifest.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node +import fs from 'fs'; +import path from 'path'; + +/** + * Implements the get-manifest script hook required by the Slack CLI. + * Prints a well-formatted structure of manifest data to stdout. + * @param {string} cwd - The current working directory of the project. + */ +(function _(cwd) { + const manifest = getManifestData(cwd); + // eslint-disable-next-line no-console + console.log(JSON.stringify(manifest)); +}(process.cwd())); + +/** + * Returns parsed manifest data for a project. + * @param {string} searchDir - The path to begin searching in. + * @returns {object} Parsed values of the project manifest. + */ +function getManifestData(searchDir) { + const manifestJSON = readManifestJSONFile(searchDir, 'manifest.json'); + if (!manifestJSON) { + throw new Error('Failed to find a manifest file in this project'); + } + return manifestJSON; +} + +/** + * Returns a manifest.json if it exists, null otherwise. + * @param {string} searchDir - Directory to begin search in. + * @param {string} filename - The file to search for. + * @returns {object | undefined} The found manifest.json object. + */ +function readManifestJSONFile(searchDir, filename) { + try { + const jsonFilePath = find(searchDir, filename); + if (jsonFilePath && fs.existsSync(jsonFilePath)) { + return JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); + } + } catch (error) { + console.error(error); // eslint-disable-line no-console + } + return undefined; +} + +/** + * Searches for a certain file in the provided file path. + * @param {string} currentPath - The current path to begin the search in. + * @param {string} targetFilename - Filename to find and match. + * @returns {string | undefined} Full file path relative to starting path. + */ +function find(currentPath, targetFilename) { + // TODO Cache searched paths and check that they haven't been explored already + // This guards against rare edge case of a subdir in the file tree which is + // symlinked back to root or in such a way that creates a cycle. Can also implement + // max depth check. + if (currentPath.endsWith(`/${targetFilename}`)) { + return currentPath; + } + + if (fs.existsSync(currentPath) && fs.lstatSync(currentPath).isDirectory()) { + const dirents = fs.readdirSync(currentPath); + return dirents.find((entry) => { + if (entry !== 'node_modules') { + const newPath = path.resolve(currentPath, entry); + return find(newPath, targetFilename); + } + return false; + }); + } + return undefined; +} diff --git a/packages/hooks/src/get-manifest.ts b/packages/hooks/src/get-manifest.ts deleted file mode 100755 index 43d450432..000000000 --- a/packages/hooks/src/get-manifest.ts +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env node -import fs from 'fs'; -import path from 'path'; - -/** - * Implements the get-manifest script hook required by the Slack CLI - * Returns a manifest JSON string to stdout. - */ -(function _(cwd: string) { - const manifest = getManifestData(cwd); - console.log(JSON.stringify(manifest)); // eslint-disable-line no-console -}(process.cwd())); - -/** - * Returns manifest data - * @param searchDir path to begin searching at - */ -function getManifestData(searchDir: string): object { - const manifestJSON = readManifestJSONFile(searchDir, 'manifest.json'); - - if (!manifestJSON) { - const msg = 'Failed to find a manifest file in this project'; - throw new Error(msg); - } - - return manifestJSON; -} - -/** - * Returns a manifest.json if it exists, null otherwise - * @param searchDir typically current working directory - * @param filename file to search for - */ -function readManifestJSONFile(searchDir: string, filename: string): object | null { - let jsonFilePath; - let manifestJSON; - - try { - jsonFilePath = find(searchDir, filename); - if (jsonFilePath && fs.existsSync(jsonFilePath)) { - manifestJSON = JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); - } - } catch (error) { - console.error(error); // eslint-disable-line no-console - return null; - } - - return manifestJSON; -} - -/** - * Search for provided file path. - * Returns full path when filename is found or null if no file found. - * @param currentPath string of current path - * @param targetFilename filename to match - * @returns full file path string relative to starting path or null - */ -function find(currentPath: string, targetFilename: string): string | undefined { - // TODO Cache searched paths and check that they haven't been explored already - // This guards against rare edge case of a subdir in the file tree which is - // symlinked back to root or in such a way that creates a cycle. Can also implement - // max depth check. - if (currentPath.endsWith(`/${targetFilename}`)) { - return currentPath; - } - - if (fs.existsSync(currentPath) && fs.lstatSync(currentPath).isDirectory()) { - const dirents = fs.readdirSync(currentPath); - return dirents.find((entry) => { - if (entry !== 'node_modules') { - const newPath = path.resolve(currentPath, entry); - return find(newPath, targetFilename); - } - return false; - }); - } - return undefined; -} diff --git a/packages/hooks/src/start.ts b/packages/hooks/src/start.js similarity index 78% rename from packages/hooks/src/start.ts rename to packages/hooks/src/start.js index bf8f0194a..49a6c14af 100755 --- a/packages/hooks/src/start.ts +++ b/packages/hooks/src/start.js @@ -5,13 +5,15 @@ import fs from 'fs'; const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf-8')); -// Run script hook verifies that requirements for running an App in -// in developerMode (via Socket Mode) are met -(function _(cwd, customPath): void { +/** + * Start hook implementation that verifies and runs an app in Socket Mode. + * @param {string} cwd - The current working directory of the project. + * @param {string | undefined} customPath - An optional path for the app. + */ +(function _(cwd, customPath) { // TODO - Format so that its less miss-able in output console.log('Preparing local run in developer mode (Socket Mode)'); // eslint-disable-line no-console - // Check required local run tokens - validate(); + validateEnvironment(); // tries the provided path, then package.json main, then defaults to index.js in the current // working directory @@ -34,7 +36,10 @@ const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf- }); }(process.cwd(), process.env.SLACK_CLI_CUSTOM_FILE_PATH)); -function validate(): void { +/** + * Confirms environment variables are prepared by the CLI. + */ +function validateEnvironment() { if (!process.env.SLACK_CLI_XOXB) { throw new Error('Missing local run bot token. Please see slack-cli maintainers to troubleshoot.'); } diff --git a/packages/hooks/tsconfig.eslint.json b/packages/hooks/tsconfig.eslint.json deleted file mode 120000 index 2cd9fb812..000000000 --- a/packages/hooks/tsconfig.eslint.json +++ /dev/null @@ -1 +0,0 @@ -../../lint-configs/tsconfig.eslint.json \ No newline at end of file From e169b708decd0d282f39a9e94ce10c6d83766146 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 10:02:20 -0800 Subject: [PATCH 06/45] test: add coverage and fix problems in the scripts --- packages/hooks/.c8rc.json | 7 + packages/hooks/.eslintrc.cjs | 8 +- packages/hooks/.gitignore | 5 +- packages/hooks/jsconfig.json | 2 +- packages/hooks/package-lock.json | 861 +++++++++++++++++++++++- packages/hooks/package.json | 14 +- packages/hooks/src/check-update.js | 27 +- packages/hooks/src/check-update.spec.js | 202 ++++++ packages/hooks/src/get-hooks.spec.js | 22 + packages/hooks/src/get-manifest.js | 13 +- packages/hooks/src/get-manifest.spec.js | 109 +++ packages/hooks/src/start.spec.js | 82 +++ 12 files changed, 1306 insertions(+), 46 deletions(-) create mode 100644 packages/hooks/.c8rc.json create mode 100644 packages/hooks/src/check-update.spec.js create mode 100644 packages/hooks/src/get-hooks.spec.js create mode 100644 packages/hooks/src/get-manifest.spec.js create mode 100644 packages/hooks/src/start.spec.js diff --git a/packages/hooks/.c8rc.json b/packages/hooks/.c8rc.json new file mode 100644 index 000000000..c13ce1948 --- /dev/null +++ b/packages/hooks/.c8rc.json @@ -0,0 +1,7 @@ +{ + "include": ["src/*.js"], + "exclude": ["**/*.spec.js"], + "reporter": ["lcov"], + "all": false, + "cache": true +} diff --git a/packages/hooks/.eslintrc.cjs b/packages/hooks/.eslintrc.cjs index ceeb67611..c18bb8330 100644 --- a/packages/hooks/.eslintrc.cjs +++ b/packages/hooks/.eslintrc.cjs @@ -19,8 +19,8 @@ module.exports = { // These environments contain lists of global variables which are allowed to be accessed env: { - // The target node version (v18) supports all important ES2021 features: https://node.green - es2021: true, + // The target node version (v18) supports all important ES2022 features: https://node.green + es2022: true, node: true, }, @@ -170,6 +170,10 @@ module.exports = { // In tests, don't force constructing a Symbol with a descriptor, as // it's probably just for tests 'symbol-description': 'off', + + 'node/no-unpublished-import': ['error', { + "allowModules": ["mocha"], + }], }, }, ], diff --git a/packages/hooks/.gitignore b/packages/hooks/.gitignore index 48344fccd..805472905 100644 --- a/packages/hooks/.gitignore +++ b/packages/hooks/.gitignore @@ -1,3 +1,6 @@ -# node / npm stuff +# Node and NPM stuff /node_modules package-lock.json + +# Coverage carryover +/coverage diff --git a/packages/hooks/jsconfig.json b/packages/hooks/jsconfig.json index fa4d6451e..d5b2894c4 100644 --- a/packages/hooks/jsconfig.json +++ b/packages/hooks/jsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2022", "module": "commonjs", "declaration": true, "declarationMap": true, diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json index c60e692a0..52d761656 100644 --- a/packages/hooks/package-lock.json +++ b/packages/hooks/package-lock.json @@ -1,12 +1,12 @@ { "name": "@slack/hooks", - "version": "0.0.4", + "version": "0.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@slack/hooks", - "version": "0.0.4", + "version": "0.0.5", "license": "MIT", "bin": { "slack-cli-check-update": "src/check-update.js", @@ -15,10 +15,13 @@ "slack-cli-start": "src/start.js" }, "devDependencies": { + "@types/mocha": "^10.0.6", "@types/node": "^20.10.8", + "c8": "^9.0.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-jsdoc": "^48.0.2", "eslint-plugin-node": "^11.1.0", + "mocha": "^10.2.0", "shx": "^0.3.4" }, "engines": { @@ -36,6 +39,12 @@ "node": ">=0.10.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.41.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", @@ -146,6 +155,40 @@ "dev": true, "peer": true }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "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.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -184,6 +227,12 @@ "node": ">= 8" } }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -191,6 +240,12 @@ "dev": true, "peer": true }, + "node_modules/@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true + }, "node_modules/@types/node": { "version": "20.10.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz", @@ -247,12 +302,20 @@ "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, - "peer": true, "engines": { "node": ">=8" } @@ -262,7 +325,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -273,6 +335,19 @@ "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/are-docs-informative": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", @@ -286,8 +361,7 @@ "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, - "peer": true + "dev": true }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", @@ -419,6 +493,15 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -429,6 +512,24 @@ "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/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -441,6 +542,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/c8": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-9.0.0.tgz", + "integrity": "sha512-nFJhU2Cz6Frh2awk3IW7wwk3wx27/U2v8ojQCHGc1GWTCHS6aMu4lal327/ZnnYj7oSThGF1X3qUP1yzAJBcOQ==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=14.14.0" + } + }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -470,7 +596,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -482,12 +607,64 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "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/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "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, - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -499,8 +676,7 @@ "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, - "peer": true + "dev": true }, "node_modules/comment-parser": { "version": "1.4.1", @@ -523,12 +699,17 @@ "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/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, - "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -593,6 +774,15 @@ "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", @@ -606,6 +796,12 @@ "node": ">=6.0.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/es-abstract": { "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", @@ -700,6 +896,15 @@ "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": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1129,12 +1334,23 @@ "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, - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -1146,6 +1362,15 @@ "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", @@ -1177,12 +1402,42 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "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", @@ -1219,6 +1474,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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-intrinsic": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", @@ -1347,7 +1611,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -1415,6 +1678,21 @@ "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/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "node_modules/ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -1516,6 +1794,18 @@ "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", @@ -1591,17 +1881,24 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "peer": 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, - "peer": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1621,6 +1918,15 @@ "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", @@ -1646,6 +1952,15 @@ "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", @@ -1719,6 +2034,18 @@ "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", @@ -1741,15 +2068,49 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "peer": true + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, "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, - "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -1829,7 +2190,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -1847,6 +2207,22 @@ "dev": true, "peer": 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/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1859,6 +2235,36 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1880,12 +2286,176 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "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": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "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/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/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/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/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/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/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -1893,6 +2463,15 @@ "dev": true, "peer": 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", @@ -2024,7 +2603,6 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -2040,7 +2618,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -2069,7 +2646,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -2088,7 +2664,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -2099,6 +2674,18 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "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/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2140,6 +2727,27 @@ ], "peer": true }, + "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/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -2181,6 +2789,15 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "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", @@ -2277,6 +2894,26 @@ "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.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -2300,6 +2937,15 @@ "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.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", @@ -2334,7 +2980,6 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -2347,7 +2992,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -2399,6 +3043,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -2421,6 +3077,20 @@ "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", "dev": true }, + "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.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -2471,7 +3141,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2494,7 +3163,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "peer": true, "engines": { "node": ">=8" }, @@ -2507,7 +3175,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2527,6 +3194,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2534,6 +3215,18 @@ "dev": true, "peer": true }, + "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": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -2669,12 +3362,25 @@ "punycode": "^2.1.0" } }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "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, - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -2720,24 +3426,121 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "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" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "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": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/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/yargs-unparser/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/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, - "peer": true, "engines": { "node": ">=10" }, diff --git a/packages/hooks/package.json b/packages/hooks/package.json index a9565a63f..aa7df2dd7 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/hooks", - "version": "0.0.4", + "version": "0.0.5", "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", @@ -12,7 +12,10 @@ "type": "module", "main": "src/get-hooks.js", "files": [ - "src/*.js" + "src/check-update.js", + "src/get-hooks.js", + "src/get-manifest.js", + "src/start.js" ], "engines": { "node": ">= 18", @@ -30,10 +33,12 @@ "url": "https://github.com/slackapi/node-slack-sdk/issues" }, "scripts": { + "prebuild": "shx rm -rf ./coverage", "build": "shx chmod +x src/*.js", "prelint": "tsc --noemit --project ./jsconfig.json", "lint": "eslint --ext .js src", - "test": "echo \"Tests are not implemented.\" && exit 0" + "pretest": "npm run lint -- --fix", + "test": "c8 mocha src/*.spec.js" }, "bin": { "slack-cli-get-hooks": "src/get-hooks.js", @@ -42,10 +47,13 @@ "slack-cli-start": "src/start.js" }, "devDependencies": { + "@types/mocha": "^10.0.6", "@types/node": "^20.10.8", + "c8": "^9.0.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-jsdoc": "^48.0.2", "eslint-plugin-node": "^11.1.0", + "mocha": "^10.2.0", "shx": "^0.3.4" } } diff --git a/packages/hooks/src/check-update.js b/packages/hooks/src/check-update.js index ebe037500..d49decddf 100755 --- a/packages/hooks/src/check-update.js +++ b/packages/hooks/src/check-update.js @@ -229,11 +229,22 @@ function getReleaseNotesUrl(packageName, latestVersion) { * @param {string | undefined} latest - Most up-to-date dependency version available. * @returns {boolean} If the update will result in a breaking change. */ -function hasAvailableUpdates(current, latest) { +export function hasAvailableUpdates(current, latest) { if (!current || !latest) { return false; } - return current !== latest; + const [currMajor, currMinor, currPatch] = current + .split('.') + .map((val) => Number(val)); + const [targetMajor, targetMinor, targetPatch] = latest + .split('.') + .map((val) => Number(val)); + if (targetMajor !== currMajor) { + return targetMajor > currMajor; + } if (targetMinor !== currMinor) { + return targetMinor > currMinor; + } + return targetPatch > currPatch; } /** @@ -242,11 +253,13 @@ function hasAvailableUpdates(current, latest) { * @param {string | undefined} latest - Most up-to-date dependency version available. * @returns {boolean} If the update will result in a breaking change. */ -function hasBreakingChange(current, latest) { +export function hasBreakingChange(current, latest) { if (!current || !latest) { return false; } - return current !== latest; + const currMajor = current.split('.')[0]; + const latestMajor = latest.split('.')[0]; + return +latestMajor - +currMajor >= 1; } /** @@ -301,7 +314,7 @@ function createCheckUpdateResponse(versionMap, inaccessibleFiles) { * @param {InaccessibleFile[]} inaccessibleFiles - Array of files that could not be read. * @returns {ErrorInfo | undefined} Formatted information about errors. */ -function createUpdateErrorMessage(dependencyErrors, inaccessibleFiles) { +export function createUpdateErrorMessage(dependencyErrors, inaccessibleFiles) { if (dependencyErrors.length === 0 && inaccessibleFiles.length === 0) { return undefined; } @@ -309,8 +322,8 @@ function createUpdateErrorMessage(dependencyErrors, inaccessibleFiles) { if (dependencyErrors.length > 0) { message = `An error occurred fetching updates for the following packages: ${dependencyErrors.join(', ')}\n`; } - const fileErrors = inaccessibleFiles.map((file) => `\n ${file.name}: ${file.error}`); - if (dependencyErrors.length > 0) { + const fileErrors = inaccessibleFiles.map((file) => ` ${file.name}: ${file.error}\n`); + if (inaccessibleFiles.length > 0) { message += `An error occurred while reading the following files:\n${fileErrors.join('')}`; } return { message }; diff --git a/packages/hooks/src/check-update.spec.js b/packages/hooks/src/check-update.spec.js new file mode 100644 index 000000000..d92e13c96 --- /dev/null +++ b/packages/hooks/src/check-update.spec.js @@ -0,0 +1,202 @@ +import { after, before, describe, it } from 'mocha'; +import assert from 'assert'; +import childProcess from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import util from 'util'; + +// Gather certain functions to test specifics without logging. +// +// eslint-disable-next-line import/extensions +import { hasAvailableUpdates, hasBreakingChange, createUpdateErrorMessage } from './check-update.js'; + +// eslint-disable-next-line no-console +console.log = function () { }; + +const exec = util.promisify(childProcess.exec); + +/** + * Mock dependency information for packages of the project. + */ +const packageJSON = { + name: 'Example application', + dependencies: { + '@slack/bolt': '^3.0.0', + '@slack/deno-slack-sdk': '^2.0.0', + }, + devDependencies: { + '@slack/hooks': '^0.0.1', + }, +}; + +/** + * Example package information provided as a mocked npm command. + */ +const mockNPM = `\ +#!/usr/bin/env node +const args = process.argv.slice(2).join(' '); +if (args === 'info @slack/bolt version --tag latest') { + console.log('3.1.4'); +} else if (args === 'info @slack/deno-slack-sdk version --tag latest') { + console.log('2.0.0'); +} else if (args === 'info @slack/hooks version --tag latest') { + console.log('1.0.1'); +} +if (args === 'list @slack/bolt --depth=0 --json') { + console.log('{"dependencies":{"@slack/bolt":{"version":"3.0.0"}}}'); +} else if (args === 'list @slack/deno-slack-sdk --depth=0 --json') { + console.log('{"dependencies":{"@slack/deno-slack-sdk":{"version":"2.0.0"}}}'); +} else if (args === 'list @slack/hooks --depth=0 --json') { + console.log('{"dependencies":{"@slack/hooks":{"version":"0.0.1"}}}'); +} +`; + +describe('check-update implementation', async () => { + describe('collects recent package versions', async () => { + before(() => { + const tempDir = path.join(process.cwd(), 'tmp'); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + const packageJSONFilePath = path.join(tempDir, 'package.json'); + fs.writeFileSync(packageJSONFilePath, JSON.stringify(packageJSON, null, 2)); + const npmFilePath = path.join(tempDir, 'npm'); + fs.writeFileSync(npmFilePath, mockNPM); + fs.chmodSync(npmFilePath, 0o755); + }); + + after(() => { + const tempDir = path.join(process.cwd(), 'tmp'); + const filePath = path.join(tempDir, 'npm'); + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); + + it('shows version information for packages', async () => { + const env = { ...process.env }; + env.PATH = `./:${env.PATH}`; + const { stdout } = await exec('../src/check-update.js', { cwd: './tmp', env }); + const updates = JSON.parse(stdout); + const expected = { + name: 'the Slack SDK', + message: '', + releases: [ + { + name: '@slack/bolt', + current: '3.0.0', + latest: '3.1.4', + update: true, + breaking: false, + url: 'https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@3.1.4', + }, + { + name: '@slack/deno-slack-sdk', + current: '2.0.0', + latest: '2.0.0', + update: false, + breaking: false, + }, + { + name: '@slack/hooks', + current: '0.0.1', + latest: '1.0.1', + update: true, + breaking: true, + url: 'https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/hooks@1.0.1', + }, + ], + url: 'https://api.slack.com/automation/changelog', + }; + assert.deepEqual(updates, expected); + }); + }); + + describe('determines the type of update', async () => { + it('should return if updates are available', () => { + assert(hasAvailableUpdates('0.0.1', '0.0.2')); + assert(hasAvailableUpdates('0.0.1', '0.2.0')); + assert(hasAvailableUpdates('0.0.1', '2.0.0')); + assert(hasAvailableUpdates('0.1.0', '0.1.1')); + assert(hasAvailableUpdates('0.1.0', '0.2.0')); + assert(hasAvailableUpdates('0.1.0', '2.0.0')); + assert(hasAvailableUpdates('1.0.0', '1.0.1')); + assert(hasAvailableUpdates('1.0.0', '1.1.0')); + assert(hasAvailableUpdates('1.0.0', '1.1.1')); + assert(hasAvailableUpdates('1.0.0', '2.0.0')); + assert(hasAvailableUpdates('0.0.2', '0.0.13')); + assert(!hasAvailableUpdates('0.0.1', '0.0.1')); + assert(!hasAvailableUpdates('0.1.0', '0.1.0')); + assert(!hasAvailableUpdates('0.1.1', '0.1.1')); + assert(!hasAvailableUpdates('1.0.0', '1.0.0')); + assert(!hasAvailableUpdates('1.0.1', '1.0.1')); + assert(!hasAvailableUpdates('1.1.1', '1.1.1')); + assert(!hasAvailableUpdates(undefined, undefined)); + assert(!hasAvailableUpdates('1.0.0', undefined)); + assert(!hasAvailableUpdates('2.0.0', '1.0.0')); + assert(!hasAvailableUpdates('2.0.0', '0.1.0')); + assert(!hasAvailableUpdates('2.0.0', '0.3.0')); + assert(!hasAvailableUpdates('2.0.0', '0.0.1')); + assert(!hasAvailableUpdates('2.0.0', '0.0.3')); + assert(!hasAvailableUpdates('2.0.0', '1.1.0')); + assert(!hasAvailableUpdates('2.0.0', '1.3.0')); + assert(!hasAvailableUpdates('2.0.0', '1.1.1')); + assert(!hasAvailableUpdates('2.0.0', '1.3.3')); + assert(!hasAvailableUpdates('0.2.0', '0.1.0')); + assert(!hasAvailableUpdates('0.2.0', '0.0.1')); + assert(!hasAvailableUpdates('0.2.0', '0.0.3')); + assert(!hasAvailableUpdates('0.2.0', '0.1.1')); + assert(!hasAvailableUpdates('0.2.0', '0.1.3')); + assert(!hasAvailableUpdates('0.0.2', '0.0.1')); + assert(!hasAvailableUpdates('0.0.20', '0.0.13')); + }); + + it('should return if the update is major', () => { + assert(hasBreakingChange('0.0.1', '1.0.0')); + assert(hasBreakingChange('0.2.3', '1.0.0')); + assert(hasBreakingChange('0.2.3', '2.0.0')); + assert(hasBreakingChange('1.0.0', '4.0.0')); + assert(!hasBreakingChange('1.0.0', '1.0.0')); + assert(!hasBreakingChange('1.0.0', '1.0.1')); + assert(!hasBreakingChange('1.0.0', '1.2.3')); + }); + }); + + describe('error messages are formatted', async () => { + it('should not note nonexistant errors', () => { + const message = createUpdateErrorMessage([], []); + const expected = undefined; + assert.deepEqual(message, expected); + }); + + it('should note package update errors', () => { + const message = createUpdateErrorMessage(['@slack/bolt'], []); + const expected = { + message: 'An error occurred fetching updates for the following packages: @slack/bolt\n', + }; + assert.deepEqual(message, expected); + }); + + it('should note any file access errors', () => { + const fileError = { name: 'package.json', error: 'Not found' }; + const message = createUpdateErrorMessage([], [fileError]); + const expected = { + message: 'An error occurred while reading the following files:\n package.json: Not found\n', + }; + assert.deepEqual(message, expected); + }); + + it('should note all errors together', () => { + const fileError = { name: 'package.json', error: 'Not found' }; + const message = createUpdateErrorMessage(['@slack/hooks'], [fileError]); + const expected = { + message: 'An error occurred fetching updates for the following packages: @slack/hooks\n' + + 'An error occurred while reading the following files:\n package.json: Not found\n', + }; + assert.deepEqual(message, expected); + }); + }); +}); diff --git a/packages/hooks/src/get-hooks.spec.js b/packages/hooks/src/get-hooks.spec.js new file mode 100644 index 000000000..fdfe39580 --- /dev/null +++ b/packages/hooks/src/get-hooks.spec.js @@ -0,0 +1,22 @@ +import { describe, it } from 'mocha'; +import assert from 'assert'; +import childProcess from 'child_process'; +import util from 'util'; + +const exec = util.promisify(childProcess.exec); + +describe('get-hooks implementation', async () => { + it('should return scripts for required hooks', async () => { + const { stdout } = await exec('./src/get-hooks.js'); + const { hooks } = JSON.parse(stdout.trim()); + assert(hooks['get-manifest'] === 'npx -q --no-install -p @slack/hooks slack-cli-get-manifest'); + assert(hooks['check-update'] === 'npx -q --no-install -p @slack/hooks slack-cli-check-update'); + assert(hooks.start === 'npx -q --no-install -p @slack/hooks slack-cli-start'); + }); + + it('should return a true managed connection', async () => { + const { stdout } = await exec('./src/get-hooks.js'); + const { config } = JSON.parse(stdout.trim()); + assert(config['sdk-managed-connection-enabled']); + }); +}); diff --git a/packages/hooks/src/get-manifest.js b/packages/hooks/src/get-manifest.js index 65d69aea1..f1e0aeed4 100755 --- a/packages/hooks/src/get-manifest.js +++ b/packages/hooks/src/get-manifest.js @@ -40,6 +40,7 @@ function readManifestJSONFile(searchDir, filename) { } } catch (error) { console.error(error); // eslint-disable-line no-console + throw new Error('Failed to parse the manifest file for this project'); } return undefined; } @@ -59,15 +60,21 @@ function find(currentPath, targetFilename) { return currentPath; } + /** @type {string | undefined} */ + let targetPath; if (fs.existsSync(currentPath) && fs.lstatSync(currentPath).isDirectory()) { const dirents = fs.readdirSync(currentPath); - return dirents.find((entry) => { + dirents.some((entry) => { if (entry !== 'node_modules') { const newPath = path.resolve(currentPath, entry); - return find(newPath, targetFilename); + const foundEntry = find(newPath, targetFilename); + if (foundEntry) { + targetPath = foundEntry; + return true; + } } return false; }); } - return undefined; + return targetPath; } diff --git a/packages/hooks/src/get-manifest.spec.js b/packages/hooks/src/get-manifest.spec.js new file mode 100644 index 000000000..60294fd69 --- /dev/null +++ b/packages/hooks/src/get-manifest.spec.js @@ -0,0 +1,109 @@ +import { after, before, describe, it } from 'mocha'; +import assert from 'assert'; +import childProcess from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import util from 'util'; + +const exec = util.promisify(childProcess.exec); + +describe('get-manifest implementation', async () => { + describe('missing project manifest file', async () => { + it('should error if no manifest.json exists', async () => { + try { + await exec('./src/get-manifest.js'); + } catch (err) { + if (err instanceof Error) { + assert(err.message.includes('Error: Failed to find a manifest file in this project')); + return; + } + } + assert(false); + }); + }); + + describe('broken project manifest file exists', async () => { + before(() => { + const tempDir = path.join(process.cwd(), 'tmp'); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + const filePath = path.join(tempDir, 'manifest.json'); + fs.writeFileSync(filePath, '{'); + }); + + after(() => { + const tempDir = path.join(process.cwd(), 'tmp'); + const filePath = path.join(tempDir, 'manifest.json'); + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); + + it('should error for invalid manifest.json', async () => { + try { + await exec('./src/get-manifest.js'); + } catch (err) { + if (err instanceof Error) { + assert(err.message.includes("SyntaxError: Expected property name or '}' in JSON at position 1")); + assert(err.message.includes('Error: Failed to parse the manifest file for this project')); + return; + } + } + assert(false); + }); + }); + + describe('contains project manifest file', async () => { + const manifest = { + display_information: { + name: 'Example app', + }, + functions: { + sample_function: { + title: 'Sample function', + description: 'Runs a sample function', + input_parameters: { + sample_input: { + title: 'Sample input text', + }, + }, + }, + }, + }; + + before(() => { + const tempDir = path.join(process.cwd(), 'tmp'); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + const filePath = path.join(tempDir, 'manifest.json'); + fs.writeFileSync(filePath, JSON.stringify(manifest, null, 2)); + }); + + after(() => { + const tempDir = path.join(process.cwd(), 'tmp'); + const filePath = path.join(tempDir, 'manifest.json'); + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); + + it('should return existing manifest values', async () => { + try { + const { stdout } = await exec('./src/get-manifest.js'); + const parsedManifest = JSON.parse(stdout); + assert.deepEqual(manifest, parsedManifest); + } catch (err) { + console.error(err); // eslint-disable-line no-console + assert(false); + } + }); + }); +}); diff --git a/packages/hooks/src/start.spec.js b/packages/hooks/src/start.spec.js new file mode 100644 index 000000000..2e126d759 --- /dev/null +++ b/packages/hooks/src/start.spec.js @@ -0,0 +1,82 @@ +import { after, afterEach, before, describe, it } from 'mocha'; +import assert from 'assert'; +import childProcess from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import util from 'util'; + +const exec = util.promisify(childProcess.exec); + +describe('start implementation', async () => { + describe('begins the app process', async () => { + const appScript = `\ +console.log("coffee"); +console.error("sips"); +`; + before(() => { + process.env.SLACK_CLI_XAPP = 'xapp-example'; + process.env.SLACK_CLI_XOXB = 'xoxb-example'; + process.env.SLACK_CLI_CUSTOM_FILE_PATH = 'tmp/app.js'; + const tempDir = path.join(process.cwd(), 'tmp'); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + const filePath = path.join(tempDir, 'app.js'); + fs.writeFileSync(filePath, appScript); + }); + + after(() => { + delete process.env.SLACK_CLI_XOXB; + delete process.env.SLACK_CLI_XAPP; + const tempDir = path.join(process.cwd(), 'tmp'); + const filePath = path.join(tempDir, 'app.js'); + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); + + it('writes output from the app script', async () => { + const { stdout, stderr } = await exec('./src/start.js'); + assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); + assert(stdout.includes('coffee')); + assert(stderr.includes('sips')); + assert(stdout.includes('bolt-app local run exited with code 0')); + }); + }); + + describe('withot valid tokens', async () => { + afterEach(() => { + delete process.env.SLACK_CLI_XOXB; + delete process.env.SLACK_CLI_XAPP; + }); + + it('should error without a bot token', async () => { + try { + process.env.SLACK_CLI_XAPP = 'xapp-example'; + await exec('./src/start.js'); + } catch (err) { + if (err instanceof Error) { + assert(err.message.includes('Error: Missing local run bot token')); + return; + } + } + assert(false); + }); + + it('should error without an app token', async () => { + try { + process.env.SLACK_CLI_XOXB = 'xoxb-example'; + await exec('./src/start.js'); + } catch (err) { + if (err instanceof Error) { + assert(err.message.includes('Error: Missing local run app token')); + return; + } + } + assert(false); + }); + }); +}); From 63ba992c4a9334974e1767f43e9a4d7f97dbae9c Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 11:22:41 -0800 Subject: [PATCH 07/45] ci: include the hooks package in automated tests --- .github/workflows/ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 96b9bf956..70a8f3a30 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: node-version: [18.x, 20.x] - package: [packages/logger, packages/oauth, packages/rtm-api, packages/socket-mode, packages/types, packages/web-api, packages/webhook] + package: [packages/hooks, packages/logger, packages/oauth, packages/rtm-api, packages/socket-mode, packages/types, packages/web-api, packages/webhook] steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} From bd4da54100c906532dcdf5048e682590faf850e1 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 11:26:43 -0800 Subject: [PATCH 08/45] ci: continue running all tests even if one fails --- .github/workflows/ci-build.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 70a8f3a30..8f1718712 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -11,9 +11,18 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 strategy: + fail-fast: false matrix: node-version: [18.x, 20.x] - package: [packages/hooks, packages/logger, packages/oauth, packages/rtm-api, packages/socket-mode, packages/types, packages/web-api, packages/webhook] + package: + - packages/hooks + - packages/logger + - packages/oauth + - packages/rtm-api + - packages/socket-mode + - packages/types + - packages/web-api + - packages/webhook steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} From cbdfb7d91ef4fda491c68dd4676a64383580d5f9 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 11:41:27 -0800 Subject: [PATCH 09/45] test: compare error outputs of different node versions --- packages/hooks/src/get-manifest.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/get-manifest.spec.js b/packages/hooks/src/get-manifest.spec.js index 60294fd69..d0fa00fb4 100644 --- a/packages/hooks/src/get-manifest.spec.js +++ b/packages/hooks/src/get-manifest.spec.js @@ -48,7 +48,9 @@ describe('get-manifest implementation', async () => { await exec('./src/get-manifest.js'); } catch (err) { if (err instanceof Error) { - assert(err.message.includes("SyntaxError: Expected property name or '}' in JSON at position 1")); + const nodeV18Error = 'SyntaxError: Unexpected end of JSON input'; + const nodeV20Error = "SyntaxError: Expected property name or '}' in JSON at position 1"; + assert(err.message.includes(nodeV20Error) || err.message.includes(nodeV18Error)); assert(err.message.includes('Error: Failed to parse the manifest file for this project')); return; } From 938dc2470bb3b32b9a9e5f1b4c9350322aee5fdd Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 16:06:28 -0800 Subject: [PATCH 10/45] docs: include instructions for app setup in the readme --- packages/hooks/README.md | 101 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index c8020947e..56202c8c3 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -1,8 +1,105 @@ # Slack CLI Hooks -Node implementations of the contract between the [Slack CLI][cli] and -[Bolt for JavaScript][bolt]. +The `@slack/hooks` package contains scripts that implement the contract between +the [Slack CLI][cli] and [Bolt for JavaScript][bolt]. + +## Requirements + +This package supports Node v18 and higher. It's highly recommended to use [the +latest LTS version of Node][node]. + +An updated version of the Slack CLI is also encouraged while using this package. + +## Installation + +Add this package as a development dependency for your project with the following +command: + +```sh +$ npm install --save-dev @slack/hooks +``` + +Follow [the installation guide][install] to download the Slack CLI and easily +run the scripts included in this package. + +## Usage + +Scripts in this package are used by the Slack CLI when running certain commands. + +These scripts are automatically added to the `./node_modules/.bin` directory of +a project when this package is installed. + +### Preparing a project manifest + +Define the [manifest of your application][manifest] in a `manifest.json` file: + +```json +{ + "display_information": { + "name": "Hooks" + }, + "settings": { + "org_deploy_enabled": true, + "socket_mode_enabled": true, + }, + "features": { + "bot_user": { + "display_name": "Hooks" + } + }, + "oauth_config": { + "scopes": { + "bot": ["chat:write"] + } + } +} +``` + +Or collect an existing manifest for your app from the **App Manifest** tab on +[App Config][config]. + +### Configuring the hooks interface + +Configure a Bolt project to use these scripts by creating a `slack.json` file in +the root directory of your project: + +```json +{ + "hooks": { + "get-hooks": "npx -q --no-install -p @slack/hooks slack-cli-get-hooks" + } +} +``` + +### Running the app + +With this package configured and the Slack CLI installed, you're ready to run +your app: + +```sh +$ slack run +``` + +## Getting help + +If you get stuck, we're here to help. The following are the best ways to get +assistance working through your issue: + +* [Issue Tracker][issues] for questions, feature requests, bug reports and + general discussion related to these packages. Try searching before you create + a new issue. +* [Email us][email]: `developers@slack.com` +* [Community Slack][community]: a Slack community for developers building all + kinds of Slack apps. You can find the maintainers and users of these packages + in **#lang-javascript**. [bolt]: https://github.com/slackapi/bolt-js [cli]: https://api.slack.com/automation/cli +[community]: https://community.slack.com/ +[config]: https://api.slack.com/apps +[email]: mailto:developers@slack.com +[install]: https://api.slack.com/automation/cli/install +[issues]: http://github.com/slackapi/node-slack-sdk/issues +[manifest]: https://api.slack.com/reference/manifests +[node]: https://github.com/nodejs/Release#release-schedule From 0fbb96e1479e072e4b166dc17ca28dd57a967ddb Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 16:19:46 -0800 Subject: [PATCH 11/45] chore: bump the package version another patch --- packages/hooks/package-lock.json | 4 ++-- packages/hooks/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json index 52d761656..438c09740 100644 --- a/packages/hooks/package-lock.json +++ b/packages/hooks/package-lock.json @@ -1,12 +1,12 @@ { "name": "@slack/hooks", - "version": "0.0.5", + "version": "0.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@slack/hooks", - "version": "0.0.5", + "version": "0.0.6", "license": "MIT", "bin": { "slack-cli-check-update": "src/check-update.js", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index aa7df2dd7..b77d4a623 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/hooks", - "version": "0.0.5", + "version": "0.0.6", "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From 54d05a94d79270ebca0e1b1c243ee757a44e1d50 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 22:08:14 -0800 Subject: [PATCH 12/45] style: improve wording and such semantics Co-authored-by: Alissa Renz --- packages/hooks/package.json | 2 +- packages/hooks/src/start.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/package.json b/packages/hooks/package.json index b77d4a623..942775bd9 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,7 +1,7 @@ { "name": "@slack/hooks", "version": "0.0.6", - "description": "Node implementations of the contract between the Slack CLI and Bolt for JavaScript", + "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", "keywords": [ diff --git a/packages/hooks/src/start.js b/packages/hooks/src/start.js index 49a6c14af..c64ca161c 100755 --- a/packages/hooks/src/start.js +++ b/packages/hooks/src/start.js @@ -32,7 +32,7 @@ const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf- }); app.on('close', (code) => { - console.log(`bolt-app local run exited with code ${code}`); // eslint-disable-line no-console + console.log(`Local run exited with code ${code}`); // eslint-disable-line no-console }); }(process.cwd(), process.env.SLACK_CLI_CUSTOM_FILE_PATH)); From 81e7a6aa19c3bd66dadf41bb603a3cd80f67b953 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 22:13:26 -0800 Subject: [PATCH 13/45] test: update expected output with actual output --- packages/hooks/src/start.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hooks/src/start.spec.js b/packages/hooks/src/start.spec.js index 2e126d759..04fd2a532 100644 --- a/packages/hooks/src/start.spec.js +++ b/packages/hooks/src/start.spec.js @@ -43,7 +43,7 @@ console.error("sips"); assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); assert(stdout.includes('coffee')); assert(stderr.includes('sips')); - assert(stdout.includes('bolt-app local run exited with code 0')); + assert(stdout.includes('Local run exited with code 0')); }); }); From 75d19942ab0fdd9670d418c993d0f012e2931d86 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 22:15:18 -0800 Subject: [PATCH 14/45] fix: remove script extensions from get-manifest --- packages/hooks/src/get-hooks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hooks/src/get-hooks.js b/packages/hooks/src/get-hooks.js index 3f967d5a1..f226fc42b 100755 --- a/packages/hooks/src/get-hooks.js +++ b/packages/hooks/src/get-hooks.js @@ -8,7 +8,7 @@ console.log(JSON.stringify({ }, config: { watch: { - 'filter-regex': '^manifest\\.(ts|js|json)$', + 'filter-regex': '^manifest\\.json$', paths: [ '.', ], From f04d115f558e33920d11e3adde2dad51e98392d9 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 10 Jan 2024 23:43:58 -0800 Subject: [PATCH 15/45] docs: switch information about setup for hooks details --- packages/hooks/README.md | 79 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 56202c8c3..5b93a758f 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -3,6 +3,18 @@ The `@slack/hooks` package contains scripts that implement the contract between the [Slack CLI][cli] and [Bolt for JavaScript][bolt]. +## Overview + +This library enables inter-process communication between the Slack CLI and +applications built with Bolt for JavaScript. + +When used together, the CLI delegates various tasks to the Bolt application by +invoking processes ("hooks") and then making use of the responses provided by +each hook's `stdout`. + +For a complete list of available hooks, read the [Supported Hooks][supported] +section. + ## Requirements This package supports Node v18 and higher. It's highly recommended to use [the @@ -24,62 +36,50 @@ run the scripts included in this package. ## Usage -Scripts in this package are used by the Slack CLI when running certain commands. +A Slack CLI-compatible Slack application includes a `slack.json` file that +contains hooks specific to that project. Each hook is associated with commands +that are available in the Slack CLI. By default, `get-hooks` retrieves all of +the [supported hooks][supported] and their corresponding scripts as defined in +this package. + +The CLI will always use the version of the `@slack/hooks` specified in the +project's `package.json`. These scripts are automatically added to the `./node_modules/.bin` directory of a project when this package is installed. -### Preparing a project manifest +### Supported Hooks -Define the [manifest of your application][manifest] in a `manifest.json` file: +The hooks that are currently supported for use within the Slack CLI include +`check-update`, `get-hooks`, `get-manifest`, and `start`: -```json -{ - "display_information": { - "name": "Hooks" - }, - "settings": { - "org_deploy_enabled": true, - "socket_mode_enabled": true, - }, - "features": { - "bot_user": { - "display_name": "Hooks" - } - }, - "oauth_config": { - "scopes": { - "bot": ["chat:write"] - } - } -} -``` +| Hook Name | CLI Command | File |Description | +| -------------- | ---------------- | ---- | ----------- | +| `check-update` | `slack update` | [`check-update.js`](./src/check-update.js) | Checks the project's Slack dependencies to determine whether or not any packages need to be updated. | +| `get-hooks` | All | [`get-hooks.js`](./src/get-hooks.js) | Fetches the list of available hooks for the CLI from this repository. | +| `get-manifest` | `slack manifest` | [`get-manifest.js`](./src/get-manifest.js) | Converts a `manifest.json` file into a valid manifest JSON payload. | +| `start` | `slack run` | [`start.js`](./src/start.js) | While developing locally, the CLI manages a socket connection with Slack's backend and utilizes this hook for events received via this connection. | -Or collect an existing manifest for your app from the **App Manifest** tab on -[App Config][config]. +### Overriding Hooks -### Configuring the hooks interface +To customize the behavior of a hook, add the hook to your application's +`slack.json` file and provide a corresponding script to be executed. -Configure a Bolt project to use these scripts by creating a `slack.json` file in -the root directory of your project: +When commands are run, the Slack CLI will look to the project's hook definitions +and use those instead of what's defined in this library, if provided. Only +[supported hooks][supported] will be recognized and executed by the Slack CLI. + +Below is an example `slack.json` file that overrides the default `start` hook: ```json { "hooks": { - "get-hooks": "npx -q --no-install -p @slack/hooks slack-cli-get-hooks" + "get-hooks": "npx -q --no-install -p @slack/hooks slack-cli-get-hooks", + "start": "npm run dev" } } ``` -### Running the app - -With this package configured and the Slack CLI installed, you're ready to run -your app: - -```sh -$ slack run -``` - ## Getting help If you get stuck, we're here to help. The following are the best ways to get @@ -103,3 +103,4 @@ assistance working through your issue: [issues]: http://github.com/slackapi/node-slack-sdk/issues [manifest]: https://api.slack.com/reference/manifests [node]: https://github.com/nodejs/Release#release-schedule +[supported]: #supported-hooks From 6866520e4d0dd970c3fa5b66f5f14a5e1f134a9d Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Thu, 11 Jan 2024 11:36:18 -0800 Subject: [PATCH 16/45] refactor: rename this package from hooks to cli-hooks --- packages/{hooks => cli-hooks}/.c8rc.json | 0 packages/{hooks => cli-hooks}/.eslintignore | 0 packages/{hooks => cli-hooks}/.eslintrc.cjs | 0 packages/{hooks => cli-hooks}/.gitignore | 0 packages/{hooks => cli-hooks}/README.md | 10 +- packages/{hooks => cli-hooks}/jsconfig.json | 0 packages/{hooks => cli-hooks}/package.json | 4 +- .../{hooks => cli-hooks}/src/check-update.js | 4 +- .../src/check-update.spec.js | 16 +- .../{hooks => cli-hooks}/src/get-hooks.js | 6 +- .../src/get-hooks.spec.js | 6 +- .../{hooks => cli-hooks}/src/get-manifest.js | 0 .../src/get-manifest.spec.js | 0 packages/{hooks => cli-hooks}/src/start.js | 0 .../{hooks => cli-hooks}/src/start.spec.js | 0 packages/hooks/package-lock.json | 3552 ----------------- 16 files changed, 23 insertions(+), 3575 deletions(-) rename packages/{hooks => cli-hooks}/.c8rc.json (100%) rename packages/{hooks => cli-hooks}/.eslintignore (100%) rename packages/{hooks => cli-hooks}/.eslintrc.cjs (100%) rename packages/{hooks => cli-hooks}/.gitignore (100%) rename packages/{hooks => cli-hooks}/README.md (92%) rename packages/{hooks => cli-hooks}/jsconfig.json (100%) rename packages/{hooks => cli-hooks}/package.json (96%) rename packages/{hooks => cli-hooks}/src/check-update.js (99%) rename packages/{hooks => cli-hooks}/src/check-update.spec.js (94%) rename packages/{hooks => cli-hooks}/src/get-hooks.js (52%) rename packages/{hooks => cli-hooks}/src/get-hooks.spec.js (82%) rename packages/{hooks => cli-hooks}/src/get-manifest.js (100%) rename packages/{hooks => cli-hooks}/src/get-manifest.spec.js (100%) rename packages/{hooks => cli-hooks}/src/start.js (100%) rename packages/{hooks => cli-hooks}/src/start.spec.js (100%) delete mode 100644 packages/hooks/package-lock.json diff --git a/packages/hooks/.c8rc.json b/packages/cli-hooks/.c8rc.json similarity index 100% rename from packages/hooks/.c8rc.json rename to packages/cli-hooks/.c8rc.json diff --git a/packages/hooks/.eslintignore b/packages/cli-hooks/.eslintignore similarity index 100% rename from packages/hooks/.eslintignore rename to packages/cli-hooks/.eslintignore diff --git a/packages/hooks/.eslintrc.cjs b/packages/cli-hooks/.eslintrc.cjs similarity index 100% rename from packages/hooks/.eslintrc.cjs rename to packages/cli-hooks/.eslintrc.cjs diff --git a/packages/hooks/.gitignore b/packages/cli-hooks/.gitignore similarity index 100% rename from packages/hooks/.gitignore rename to packages/cli-hooks/.gitignore diff --git a/packages/hooks/README.md b/packages/cli-hooks/README.md similarity index 92% rename from packages/hooks/README.md rename to packages/cli-hooks/README.md index 5b93a758f..13a270e7c 100644 --- a/packages/hooks/README.md +++ b/packages/cli-hooks/README.md @@ -1,7 +1,7 @@ # Slack CLI Hooks -The `@slack/hooks` package contains scripts that implement the contract between -the [Slack CLI][cli] and [Bolt for JavaScript][bolt]. +The `@slack/cli-hooks` package contains scripts that implement the contract +between the [Slack CLI][cli] and [Bolt for JavaScript][bolt]. ## Overview @@ -28,7 +28,7 @@ Add this package as a development dependency for your project with the following command: ```sh -$ npm install --save-dev @slack/hooks +$ npm install --save-dev @slack/cli-hooks ``` Follow [the installation guide][install] to download the Slack CLI and easily @@ -42,7 +42,7 @@ that are available in the Slack CLI. By default, `get-hooks` retrieves all of the [supported hooks][supported] and their corresponding scripts as defined in this package. -The CLI will always use the version of the `@slack/hooks` specified in the +The CLI will always use the version of the `@slack/cli-hooks` specified in the project's `package.json`. These scripts are automatically added to the `./node_modules/.bin` directory of @@ -74,7 +74,7 @@ Below is an example `slack.json` file that overrides the default `start` hook: ```json { "hooks": { - "get-hooks": "npx -q --no-install -p @slack/hooks slack-cli-get-hooks", + "get-hooks": "npx -q --no-install -p @slack/cli-hooks slack-cli-get-hooks", "start": "npm run dev" } } diff --git a/packages/hooks/jsconfig.json b/packages/cli-hooks/jsconfig.json similarity index 100% rename from packages/hooks/jsconfig.json rename to packages/cli-hooks/jsconfig.json diff --git a/packages/hooks/package.json b/packages/cli-hooks/package.json similarity index 96% rename from packages/hooks/package.json rename to packages/cli-hooks/package.json index 942775bd9..9831beda1 100644 --- a/packages/hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { - "name": "@slack/hooks", - "version": "0.0.6", + "name": "@slack/cli-hooks", + "version": "0.0.7", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", diff --git a/packages/hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js similarity index 99% rename from packages/hooks/src/check-update.js rename to packages/cli-hooks/src/check-update.js index d49decddf..e98c3dc57 100755 --- a/packages/hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -6,7 +6,7 @@ import childProcess from 'child_process'; const exec = util.promisify(childProcess.exec); const SLACK_BOLT_SDK = '@slack/bolt'; -const SLACK_CLI_HOOKS = '@slack/hooks'; +const SLACK_CLI_HOOKS = '@slack/cli-hooks'; const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; /** @@ -218,7 +218,7 @@ function getReleaseNotesUrl(packageName, latestVersion) { } if (packageName === SLACK_DENO_SDK) { return `https://github.com/slackapi/deno-slack-sdk/releases/tag/${latestVersion}`; } if (packageName === SLACK_CLI_HOOKS) { - return `https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/hooks@${latestVersion}`; + return `https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/cli-hooks@${latestVersion}`; } return undefined; } diff --git a/packages/hooks/src/check-update.spec.js b/packages/cli-hooks/src/check-update.spec.js similarity index 94% rename from packages/hooks/src/check-update.spec.js rename to packages/cli-hooks/src/check-update.spec.js index d92e13c96..207bcf466 100644 --- a/packages/hooks/src/check-update.spec.js +++ b/packages/cli-hooks/src/check-update.spec.js @@ -25,7 +25,7 @@ const packageJSON = { '@slack/deno-slack-sdk': '^2.0.0', }, devDependencies: { - '@slack/hooks': '^0.0.1', + '@slack/cli-hooks': '^0.0.1', }, }; @@ -39,15 +39,15 @@ if (args === 'info @slack/bolt version --tag latest') { console.log('3.1.4'); } else if (args === 'info @slack/deno-slack-sdk version --tag latest') { console.log('2.0.0'); -} else if (args === 'info @slack/hooks version --tag latest') { +} else if (args === 'info @slack/cli-hooks version --tag latest') { console.log('1.0.1'); } if (args === 'list @slack/bolt --depth=0 --json') { console.log('{"dependencies":{"@slack/bolt":{"version":"3.0.0"}}}'); } else if (args === 'list @slack/deno-slack-sdk --depth=0 --json') { console.log('{"dependencies":{"@slack/deno-slack-sdk":{"version":"2.0.0"}}}'); -} else if (args === 'list @slack/hooks --depth=0 --json') { - console.log('{"dependencies":{"@slack/hooks":{"version":"0.0.1"}}}'); +} else if (args === 'list @slack/cli-hooks --depth=0 --json') { + console.log('{"dependencies":{"@slack/cli-hooks":{"version":"0.0.1"}}}'); } `; @@ -101,12 +101,12 @@ describe('check-update implementation', async () => { breaking: false, }, { - name: '@slack/hooks', + name: '@slack/cli-hooks', current: '0.0.1', latest: '1.0.1', update: true, breaking: true, - url: 'https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/hooks@1.0.1', + url: 'https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/cli-hooks@1.0.1', }, ], url: 'https://api.slack.com/automation/changelog', @@ -191,9 +191,9 @@ describe('check-update implementation', async () => { it('should note all errors together', () => { const fileError = { name: 'package.json', error: 'Not found' }; - const message = createUpdateErrorMessage(['@slack/hooks'], [fileError]); + const message = createUpdateErrorMessage(['@slack/cli-hooks'], [fileError]); const expected = { - message: 'An error occurred fetching updates for the following packages: @slack/hooks\n' + + message: 'An error occurred fetching updates for the following packages: @slack/cli-hooks\n' + 'An error occurred while reading the following files:\n package.json: Not found\n', }; assert.deepEqual(message, expected); diff --git a/packages/hooks/src/get-hooks.js b/packages/cli-hooks/src/get-hooks.js similarity index 52% rename from packages/hooks/src/get-hooks.js rename to packages/cli-hooks/src/get-hooks.js index f226fc42b..ed2aeef54 100755 --- a/packages/hooks/src/get-hooks.js +++ b/packages/cli-hooks/src/get-hooks.js @@ -2,9 +2,9 @@ // eslint-disable-next-line no-console console.log(JSON.stringify({ hooks: { - 'get-manifest': 'npx -q --no-install -p @slack/hooks slack-cli-get-manifest', - 'check-update': 'npx -q --no-install -p @slack/hooks slack-cli-check-update', - start: 'npx -q --no-install -p @slack/hooks slack-cli-start', + 'get-manifest': 'npx -q --no-install -p @slack/cli-hooks slack-cli-get-manifest', + 'check-update': 'npx -q --no-install -p @slack/cli-hooks slack-cli-check-update', + start: 'npx -q --no-install -p @slack/cli-hooks slack-cli-start', }, config: { watch: { diff --git a/packages/hooks/src/get-hooks.spec.js b/packages/cli-hooks/src/get-hooks.spec.js similarity index 82% rename from packages/hooks/src/get-hooks.spec.js rename to packages/cli-hooks/src/get-hooks.spec.js index fdfe39580..7890d47ca 100644 --- a/packages/hooks/src/get-hooks.spec.js +++ b/packages/cli-hooks/src/get-hooks.spec.js @@ -9,9 +9,9 @@ describe('get-hooks implementation', async () => { it('should return scripts for required hooks', async () => { const { stdout } = await exec('./src/get-hooks.js'); const { hooks } = JSON.parse(stdout.trim()); - assert(hooks['get-manifest'] === 'npx -q --no-install -p @slack/hooks slack-cli-get-manifest'); - assert(hooks['check-update'] === 'npx -q --no-install -p @slack/hooks slack-cli-check-update'); - assert(hooks.start === 'npx -q --no-install -p @slack/hooks slack-cli-start'); + assert(hooks['get-manifest'] === 'npx -q --no-install -p @slack/cli-hooks slack-cli-get-manifest'); + assert(hooks['check-update'] === 'npx -q --no-install -p @slack/cli-hooks slack-cli-check-update'); + assert(hooks.start === 'npx -q --no-install -p @slack/cli-hooks slack-cli-start'); }); it('should return a true managed connection', async () => { diff --git a/packages/hooks/src/get-manifest.js b/packages/cli-hooks/src/get-manifest.js similarity index 100% rename from packages/hooks/src/get-manifest.js rename to packages/cli-hooks/src/get-manifest.js diff --git a/packages/hooks/src/get-manifest.spec.js b/packages/cli-hooks/src/get-manifest.spec.js similarity index 100% rename from packages/hooks/src/get-manifest.spec.js rename to packages/cli-hooks/src/get-manifest.spec.js diff --git a/packages/hooks/src/start.js b/packages/cli-hooks/src/start.js similarity index 100% rename from packages/hooks/src/start.js rename to packages/cli-hooks/src/start.js diff --git a/packages/hooks/src/start.spec.js b/packages/cli-hooks/src/start.spec.js similarity index 100% rename from packages/hooks/src/start.spec.js rename to packages/cli-hooks/src/start.spec.js diff --git a/packages/hooks/package-lock.json b/packages/hooks/package-lock.json deleted file mode 100644 index 438c09740..000000000 --- a/packages/hooks/package-lock.json +++ /dev/null @@ -1,3552 +0,0 @@ -{ - "name": "@slack/hooks", - "version": "0.0.6", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@slack/hooks", - "version": "0.0.6", - "license": "MIT", - "bin": { - "slack-cli-check-update": "src/check-update.js", - "slack-cli-get-hooks": "src/get-hooks.js", - "slack-cli-get-manifest": "src/get-manifest.js", - "slack-cli-start": "src/start.js" - }, - "devDependencies": { - "@types/mocha": "^10.0.6", - "@types/node": "^20.10.8", - "c8": "^9.0.0", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-plugin-jsdoc": "^48.0.2", - "eslint-plugin-node": "^11.1.0", - "mocha": "^10.2.0", - "shx": "^0.3.4" - }, - "engines": { - "node": ">= 18", - "npm": ">= 8.6.0" - } - }, - "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, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", - "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", - "dev": true, - "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "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, - "peer": 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/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, - "peer": 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, - "peer": 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/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", - "dev": true, - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "peer": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "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, - "peer": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true, - "peer": true - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "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.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "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, - "peer": 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, - "peer": 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, - "peer": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "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, - "peer": true - }, - "node_modules/@types/mocha": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", - "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.10.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz", - "integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "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, - "peer": 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, - "peer": 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, - "peer": 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, - "peer": 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/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "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, - "peer": 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, - "peer": 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.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/c8": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/c8/-/c8-9.0.0.tgz", - "integrity": "sha512-nFJhU2Cz6Frh2awk3IW7wwk3wx27/U2v8ojQCHGc1GWTCHS6aMu4lal327/ZnnYj7oSThGF1X3qUP1yzAJBcOQ==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^3.1.1", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.1.6", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1" - }, - "bin": { - "c8": "bin/c8.js" - }, - "engines": { - "node": ">=14.14.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "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, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "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/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/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "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/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", - "dev": true, - "engines": { - "node": ">= 12.0.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/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/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/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/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, - "peer": true - }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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, - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.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/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - }, - "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, - "peer": 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": "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": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", - "@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, - "peer": 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, - "peer": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "peer": 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, - "peer": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.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, - "peer": 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, - "peer": 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, - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "48.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.0.2.tgz", - "integrity": "sha512-CBFl5Jc7+jlV36RwDm+PQ8Uw5r28pn2/uW/OaB+Gw5bFwn4Py/1eYMZ3hGf9S4meUFZ/sRvS+hVif2mRAp6WqQ==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.41.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.5.4", - "spdx-expression-parse": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "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, - "peer": 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-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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, - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "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, - "peer": 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/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/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, - "peer": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "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/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "peer": 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, - "peer": 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, - "peer": 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, - "peer": true - }, - "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", - "dev": true, - "peer": 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, - "peer": 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, - "peer": 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.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true, - "peer": 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/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "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/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-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/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, - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "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, - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "peer": 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": "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/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "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.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "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/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/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, - "peer": 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, - "peer": 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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "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-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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-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.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "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, - "peer": 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.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "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.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "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/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "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, - "peer": 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, - "peer": 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, - "peer": true - }, - "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, - "peer": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "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, - "peer": 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, - "peer": 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.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, - "peer": 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/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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/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.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "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": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.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" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "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/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/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/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/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/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/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "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, - "peer": 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.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "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, - "peer": 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, - "peer": 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/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/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, - "peer": 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, - "peer": 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" - } - ], - "peer": true - }, - "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/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "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, - "peer": 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, - "peer": 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, - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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" - } - ], - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "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.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.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.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "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/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/shx": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", - "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", - "dev": true, - "dependencies": { - "minimist": "^1.2.3", - "shelljs": "^0.8.5" - }, - "bin": { - "shx": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true - }, - "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.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "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, - "peer": 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": "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/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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "peer": true - }, - "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": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "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, - "peer": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "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, - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "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, - "peer": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "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": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "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": { - "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" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "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" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "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": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/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/yargs-unparser/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/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": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} From 72b0d00255dc43791258a4fc88f45269056d7032 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Thu, 11 Jan 2024 11:37:32 -0800 Subject: [PATCH 17/45] fix: run tests for the newly named package instead --- .github/workflows/ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 8f1718712..877365555 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -15,7 +15,7 @@ jobs: matrix: node-version: [18.x, 20.x] package: - - packages/hooks + - packages/cli-hooks - packages/logger - packages/oauth - packages/rtm-api From c6f3da263dfc774941d99abf8e928345289461bd Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Thu, 11 Jan 2024 16:38:02 -0800 Subject: [PATCH 18/45] feat: default to an app.js script in the start hook --- packages/cli-hooks/src/start.js | 5 +- packages/cli-hooks/src/start.spec.js | 113 +++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 11 deletions(-) diff --git a/packages/cli-hooks/src/start.js b/packages/cli-hooks/src/start.js index c64ca161c..39ee904e3 100755 --- a/packages/cli-hooks/src/start.js +++ b/packages/cli-hooks/src/start.js @@ -15,9 +15,8 @@ const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf- console.log('Preparing local run in developer mode (Socket Mode)'); // eslint-disable-line no-console validateEnvironment(); - // tries the provided path, then package.json main, then defaults to index.js in the current - // working directory - const pkgJSONDefault = 'index.js'; + // Tries the provided path, then package.json main, then defaults to app.js + const pkgJSONDefault = 'app.js'; const fullPath = path.resolve(cwd, customPath || (pkgJSONMain || pkgJSONDefault)); console.log(fullPath); // eslint-disable-line no-console diff --git a/packages/cli-hooks/src/start.spec.js b/packages/cli-hooks/src/start.spec.js index 04fd2a532..e287219c0 100644 --- a/packages/cli-hooks/src/start.spec.js +++ b/packages/cli-hooks/src/start.spec.js @@ -7,22 +7,73 @@ import util from 'util'; const exec = util.promisify(childProcess.exec); -describe('start implementation', async () => { - describe('begins the app process', async () => { - const appScript = `\ +/** + * Mock app information for packages of the project. + */ +const mainPackageJSON = { name: 'Example application', main: 'start.js' }; +const defaultPackageJSON = { name: 'Example application' }; + +/** + * Mock a super simple app script to verify outputs. + */ +const appScript = `\ console.log("coffee"); console.error("sips"); `; + +describe('start implementation', async () => { + describe('begins the main app process', async () => { before(() => { process.env.SLACK_CLI_XAPP = 'xapp-example'; process.env.SLACK_CLI_XOXB = 'xoxb-example'; - process.env.SLACK_CLI_CUSTOM_FILE_PATH = 'tmp/app.js'; const tempDir = path.join(process.cwd(), 'tmp'); if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir); } - const filePath = path.join(tempDir, 'app.js'); - fs.writeFileSync(filePath, appScript); + const appFilePath = path.join(tempDir, 'start.js'); + fs.writeFileSync(appFilePath, appScript); + const packageJSONFilePath = path.join(tempDir, 'package.json'); + fs.writeFileSync(packageJSONFilePath, JSON.stringify(mainPackageJSON, null, 2)); + }); + + after(() => { + delete process.env.SLACK_CLI_XOXB; + delete process.env.SLACK_CLI_XAPP; + const tempDir = path.join(process.cwd(), 'tmp'); + const appFilePath = path.join(tempDir, 'start.js'); + if (fs.existsSync(appFilePath)) { + fs.unlinkSync(appFilePath); + } + const packageJSONFilePath = path.join(tempDir, 'package.json'); + if (fs.existsSync(packageJSONFilePath)) { + fs.unlinkSync(packageJSONFilePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); + + it('writes output from the main script', async () => { + const { stdout, stderr } = await exec('../src/start.js', { cwd: './tmp' }); + assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); + assert(stdout.includes('coffee')); + assert(stderr.includes('sips')); + assert(stdout.includes('Local run exited with code 0')); + }); + }); + + describe('begins the default app process', async () => { + before(() => { + process.env.SLACK_CLI_XAPP = 'xapp-example'; + process.env.SLACK_CLI_XOXB = 'xoxb-example'; + const tempDir = path.join(process.cwd(), 'tmp'); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + const appFilePath = path.join(tempDir, 'app.js'); + fs.writeFileSync(appFilePath, appScript); + const packageJSONFilePath = path.join(tempDir, 'package.json'); + fs.writeFileSync(packageJSONFilePath, JSON.stringify(defaultPackageJSON, null, 2)); }); after(() => { @@ -33,13 +84,59 @@ console.error("sips"); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } + const packageJSONFilePath = path.join(tempDir, 'package.json'); + if (fs.existsSync(packageJSONFilePath)) { + fs.unlinkSync(packageJSONFilePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); + + it('writes output from the default script', async () => { + const { stdout, stderr } = await exec('../src/start.js', { cwd: './tmp' }); + assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); + assert(stdout.includes('coffee')); + assert(stderr.includes('sips')); + assert(stdout.includes('Local run exited with code 0')); + }); + }); + + describe('begins the custom app process', async () => { + before(() => { + process.env.SLACK_CLI_XAPP = 'xapp-example'; + process.env.SLACK_CLI_XOXB = 'xoxb-example'; + process.env.SLACK_CLI_CUSTOM_FILE_PATH = 'application.js'; + const tempDir = path.join(process.cwd(), 'tmp'); + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + const appFilePath = path.join(tempDir, 'application.js'); + fs.writeFileSync(appFilePath, appScript); + const packageJSONFilePath = path.join(tempDir, 'package.json'); + fs.writeFileSync(packageJSONFilePath, JSON.stringify(mainPackageJSON, null, 2)); + }); + + after(() => { + delete process.env.SLACK_CLI_XOXB; + delete process.env.SLACK_CLI_XAPP; + delete process.env.SLACK_CLI_CUSTOM_FILE_PATH; + const tempDir = path.join(process.cwd(), 'tmp'); + const appFilePath = path.join(tempDir, 'application.js'); + if (fs.existsSync(appFilePath)) { + fs.unlinkSync(appFilePath); + } + const packageJSONFilePath = path.join(tempDir, 'package.json'); + if (fs.existsSync(packageJSONFilePath)) { + fs.unlinkSync(packageJSONFilePath); + } if (fs.existsSync(tempDir)) { fs.rmSync(tempDir, { recursive: true }); } }); - it('writes output from the app script', async () => { - const { stdout, stderr } = await exec('./src/start.js'); + it('writes output from the custom script', async () => { + const { stdout, stderr } = await exec('../src/start.js', { cwd: './tmp' }); assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); assert(stdout.includes('coffee')); assert(stderr.includes('sips')); From e8963b10e67b278d0bfa1d15946c7e7f72be46c0 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Tue, 23 Jan 2024 11:46:02 -0800 Subject: [PATCH 19/45] fix: lookup manifest file across different operating systems --- packages/cli-hooks/src/get-manifest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli-hooks/src/get-manifest.js b/packages/cli-hooks/src/get-manifest.js index f1e0aeed4..3799f0068 100755 --- a/packages/cli-hooks/src/get-manifest.js +++ b/packages/cli-hooks/src/get-manifest.js @@ -56,8 +56,8 @@ function find(currentPath, targetFilename) { // This guards against rare edge case of a subdir in the file tree which is // symlinked back to root or in such a way that creates a cycle. Can also implement // max depth check. - if (currentPath.endsWith(`/${targetFilename}`)) { - return currentPath; + if (fs.existsSync(path.join(currentPath, targetFilename))) { + return path.join(currentPath, targetFilename); } /** @type {string | undefined} */ From 02dc94698798c52fae99fcf86da79b278ac48a66 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Tue, 23 Jan 2024 11:50:15 -0800 Subject: [PATCH 20/45] chore: bump the package patch version --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 9831beda1..1a7d20bdf 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.7", + "version": "0.0.8", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From a800d5ab135834d5232f9d64d9ba6443f8b5fc82 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 00:40:16 -0800 Subject: [PATCH 21/45] refactor: export hook as modules instead of iife scripts --- packages/cli-hooks/.eslintrc.cjs | 14 +- packages/cli-hooks/jsconfig.json | 11 +- packages/cli-hooks/package.json | 6 +- packages/cli-hooks/src/check-update.js | 29 ++- packages/cli-hooks/src/check-update.spec.js | 93 ++++---- packages/cli-hooks/src/get-hooks.js | 75 +++++-- packages/cli-hooks/src/get-hooks.spec.js | 10 +- packages/cli-hooks/src/get-manifest.js | 27 ++- packages/cli-hooks/src/get-manifest.spec.js | 28 +-- packages/cli-hooks/src/start.js | 46 ++-- packages/cli-hooks/src/start.spec.js | 228 ++++++++++---------- 11 files changed, 317 insertions(+), 250 deletions(-) diff --git a/packages/cli-hooks/.eslintrc.cjs b/packages/cli-hooks/.eslintrc.cjs index c18bb8330..19f0e0509 100644 --- a/packages/cli-hooks/.eslintrc.cjs +++ b/packages/cli-hooks/.eslintrc.cjs @@ -9,17 +9,20 @@ // These styles are a subset of the shared JavaScript and TypeScript configurations to only target JavaScript packages. module.exports = { - // This is a root of the project, ESLint should not look through parent directories to find more config root: true, + parserOptions: { + ecmaVersion: 2022 + }, + // Ignore all build outputs and artifacts (node_modules, dotfiles, and dot directories are implicitly ignored) ignorePatterns: [ - // Ignore all build outputs and artifacts (node_modules, dotfiles, and dot directories are implicitly ignored) '/coverage', ], // These environments contain lists of global variables which are allowed to be accessed + // + // The target node version (v18) supports all needed ES2022 features: https://node.green env: { - // The target node version (v18) supports all important ES2022 features: https://node.green es2022: true, node: true, }, @@ -76,6 +79,11 @@ module.exports = { 'import/named': 'off', 'node/no-missing-import': 'off', + // Require extensions for imported modules + 'import/extensions': ['error', 'ignorePackages', { + 'js': 'always', + }], + // Allow use of import and export syntax, despite it not being supported in the node versions. Since this // project is transpiled, the ignore option is used. Overrides node/recommended. 'node/no-unsupported-features/es-syntax': ['error', { ignores: ['modules'] }], diff --git a/packages/cli-hooks/jsconfig.json b/packages/cli-hooks/jsconfig.json index d5b2894c4..2e3e52e08 100644 --- a/packages/cli-hooks/jsconfig.json +++ b/packages/cli-hooks/jsconfig.json @@ -1,11 +1,8 @@ { "compilerOptions": { - "target": "es2022", - "module": "commonjs", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "outDir": "dist", + "module": "es2022", + "moduleResolution": "node", + "esModuleInterop" : true, "checkJs": true, "strict": true, @@ -14,12 +11,10 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", "baseUrl": ".", "paths": { "*": ["./types/*"] }, - "esModuleInterop" : true, }, "include": [ "src/**/*" diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 1a7d20bdf..da53c5529 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -35,7 +35,7 @@ "scripts": { "prebuild": "shx rm -rf ./coverage", "build": "shx chmod +x src/*.js", - "prelint": "tsc --noemit --project ./jsconfig.json", + "prelint": "tsc --noemit --module es2022 --project ./jsconfig.json", "lint": "eslint --ext .js src", "pretest": "npm run lint -- --fix", "test": "c8 mocha src/*.spec.js" @@ -49,11 +49,13 @@ "devDependencies": { "@types/mocha": "^10.0.6", "@types/node": "^20.10.8", + "@types/sinon": "^17.0.3", "c8": "^9.0.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-jsdoc": "^48.0.2", "eslint-plugin-node": "^11.1.0", "mocha": "^10.2.0", - "shx": "^0.3.4" + "shx": "^0.3.4", + "sinon": "^17.0.1" } } diff --git a/packages/cli-hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js index e98c3dc57..cadd2f199 100755 --- a/packages/cli-hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -1,14 +1,23 @@ #!/usr/bin/env node + +import { fileURLToPath } from 'url'; +import childProcess from 'child_process'; import fs from 'fs'; import util from 'util'; -import childProcess from 'child_process'; - -const exec = util.promisify(childProcess.exec); const SLACK_BOLT_SDK = '@slack/bolt'; const SLACK_CLI_HOOKS = '@slack/cli-hooks'; const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; +/** + * Implementation of the check-update hook that finds available SDK updates. + * Prints an object detailing information on Slack dependencies for the CLI. + */ + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + checkForSDKUpdates(process.cwd()).then(JSON.stringify).then(console.log); // eslint-disable-line no-console +} + /** * @typedef {object} UpdateInfo * @property {string} name - Overall identifier of the package. @@ -42,23 +51,12 @@ const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; * @property {unknown} error - Cause of the failure. */ -/** - * Implementation of the check-update hook that finds available SDK updates. - * Prints an object detailing information on Slack dependencies for the CLI. - * @param {string} cwd - The current working directory of the project. - */ -(async function _(cwd) { - const updates = await checkForSDKUpdates(cwd); - // eslint-disable-next-line no-console - console.log(JSON.stringify(updates)); // stdout -}(process.cwd())); - /** * Checks for available SDK updates of specified Slack dependencies. * @param {string} cwd - The current working directory of the CLI project. * @returns {Promise} Formatted package version information. */ -async function checkForSDKUpdates(cwd) { +export default async function checkForSDKUpdates(cwd) { const { versionMap, inaccessibleFiles } = await getProjectDependencies(cwd); const checkUpdateResponse = createCheckUpdateResponse(versionMap, inaccessibleFiles); return checkUpdateResponse; @@ -268,6 +266,7 @@ export function hasBreakingChange(current, latest) { * @returns {Promise} the output from the command. */ async function execWrapper(command) { + const exec = util.promisify(childProcess.exec); const { stdout } = await exec(command); return stdout.trim(); } diff --git a/packages/cli-hooks/src/check-update.spec.js b/packages/cli-hooks/src/check-update.spec.js index 207bcf466..db8a08ce0 100644 --- a/packages/cli-hooks/src/check-update.spec.js +++ b/packages/cli-hooks/src/check-update.spec.js @@ -1,19 +1,15 @@ import { after, before, describe, it } from 'mocha'; import assert from 'assert'; -import childProcess from 'child_process'; import fs from 'fs'; import path from 'path'; +import sinon from 'sinon'; import util from 'util'; -// Gather certain functions to test specifics without logging. -// -// eslint-disable-next-line import/extensions -import { hasAvailableUpdates, hasBreakingChange, createUpdateErrorMessage } from './check-update.js'; - -// eslint-disable-next-line no-console -console.log = function () { }; - -const exec = util.promisify(childProcess.exec); +import checkForSDKUpdates, { + hasAvailableUpdates, + hasBreakingChange, + createUpdateErrorMessage, +} from './check-update.js'; /** * Mock dependency information for packages of the project. @@ -31,45 +27,55 @@ const packageJSON = { /** * Example package information provided as a mocked npm command. + * @param {string} command - Command to mock a result for. + * @returns {string} - Stringified result of the mocked command. */ -const mockNPM = `\ -#!/usr/bin/env node -const args = process.argv.slice(2).join(' '); -if (args === 'info @slack/bolt version --tag latest') { - console.log('3.1.4'); -} else if (args === 'info @slack/deno-slack-sdk version --tag latest') { - console.log('2.0.0'); -} else if (args === 'info @slack/cli-hooks version --tag latest') { - console.log('1.0.1'); +function mockNPM(command) { + if (command === 'npm info @slack/bolt version --tag latest') { + return '3.1.4'; + } if (command === 'npm info @slack/deno-slack-sdk version --tag latest') { + return '2.0.0'; + } if (command === 'npm info @slack/cli-hooks version --tag latest') { + return '1.0.1'; + } + if (command === 'npm list @slack/bolt --depth=0 --json') { + return '{"dependencies":{"@slack/bolt":{"version":"3.0.0"}}}'; + } if (command === 'npm list @slack/deno-slack-sdk --depth=0 --json') { + return '{"dependencies":{"@slack/deno-slack-sdk":{"version":"2.0.0"}}}'; + } if (command === 'npm list @slack/cli-hooks --depth=0 --json') { + return '{"dependencies":{"@slack/cli-hooks":{"version":"0.0.1"}}}'; + } + throw new Error('Unknown NPM command mocked'); } -if (args === 'list @slack/bolt --depth=0 --json') { - console.log('{"dependencies":{"@slack/bolt":{"version":"3.0.0"}}}'); -} else if (args === 'list @slack/deno-slack-sdk --depth=0 --json') { - console.log('{"dependencies":{"@slack/deno-slack-sdk":{"version":"2.0.0"}}}'); -} else if (args === 'list @slack/cli-hooks --depth=0 --json') { - console.log('{"dependencies":{"@slack/cli-hooks":{"version":"0.0.1"}}}'); -} -`; + +/** + * @typedef MockExecProcess + * @property {string} stdout - Output logged to standard output streams. + * @property {string} stderr - Output logged to standard error streams. + */ describe('check-update implementation', async () => { describe('collects recent package versions', async () => { + const tempDir = path.join(process.cwd(), 'tmp'); + const packageJSONFilePath = path.join(tempDir, 'package.json'); before(() => { - const tempDir = path.join(process.cwd(), 'tmp'); + sinon.stub(util, 'promisify') + .returns((/** @type {string} */ command) => { + const info = mockNPM(command); + return Promise.resolve({ stdout: info }); + }); if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir); } - const packageJSONFilePath = path.join(tempDir, 'package.json'); - fs.writeFileSync(packageJSONFilePath, JSON.stringify(packageJSON, null, 2)); - const npmFilePath = path.join(tempDir, 'npm'); - fs.writeFileSync(npmFilePath, mockNPM); - fs.chmodSync(npmFilePath, 0o755); + if (!fs.existsSync(packageJSONFilePath)) { + fs.writeFileSync(packageJSONFilePath, JSON.stringify(packageJSON, null, 2)); + } }); after(() => { - const tempDir = path.join(process.cwd(), 'tmp'); - const filePath = path.join(tempDir, 'npm'); - if (fs.existsSync(filePath)) { - fs.unlinkSync(filePath); + sinon.restore(); + if (fs.existsSync(packageJSONFilePath)) { + fs.unlinkSync(packageJSONFilePath); } if (fs.existsSync(tempDir)) { fs.rmSync(tempDir, { recursive: true }); @@ -77,19 +83,19 @@ describe('check-update implementation', async () => { }); it('shows version information for packages', async () => { - const env = { ...process.env }; - env.PATH = `./:${env.PATH}`; - const { stdout } = await exec('../src/check-update.js', { cwd: './tmp', env }); - const updates = JSON.parse(stdout); + const updates = await checkForSDKUpdates('./tmp'); const expected = { name: 'the Slack SDK', + error: undefined, message: '', releases: [ { name: '@slack/bolt', current: '3.0.0', latest: '3.1.4', + error: undefined, update: true, + message: undefined, breaking: false, url: 'https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@3.1.4', }, @@ -97,14 +103,19 @@ describe('check-update implementation', async () => { name: '@slack/deno-slack-sdk', current: '2.0.0', latest: '2.0.0', + error: undefined, update: false, + message: undefined, breaking: false, + url: undefined, }, { name: '@slack/cli-hooks', current: '0.0.1', latest: '1.0.1', + error: undefined, update: true, + message: undefined, breaking: true, url: 'https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/cli-hooks@1.0.1', }, diff --git a/packages/cli-hooks/src/get-hooks.js b/packages/cli-hooks/src/get-hooks.js index ed2aeef54..e2abb8e74 100755 --- a/packages/cli-hooks/src/get-hooks.js +++ b/packages/cli-hooks/src/get-hooks.js @@ -1,18 +1,61 @@ #!/usr/bin/env node -// eslint-disable-next-line no-console -console.log(JSON.stringify({ - hooks: { - 'get-manifest': 'npx -q --no-install -p @slack/cli-hooks slack-cli-get-manifest', - 'check-update': 'npx -q --no-install -p @slack/cli-hooks slack-cli-check-update', - start: 'npx -q --no-install -p @slack/cli-hooks slack-cli-start', - }, - config: { - watch: { - 'filter-regex': '^manifest\\.json$', - paths: [ - '.', - ], + +import { fileURLToPath } from 'url'; + +/** + * Implementation the get-hooks script hook required by the Slack CLI. + * Printed as an object containing featured provided by the SDK. + */ + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + console.log(JSON.stringify(getHooks())); // eslint-disable-line no-console +} + +/** + * Standardized communication format between the SDK and CLI regarding hooks. + * @typedef SDKInterface + * @property {Record} hooks - Commands available in the package. + * @property {SDKConfig} config - Settings for SDK and CLI communication. + * @property {string} runtime - Target runtime that app functions execute in. + */ + +/** + * Additional configurations provided to the CLI about the SDK. + * @typedef SDKConfig + * @property {string[]} protocol-version - Named CLI protocols used by the SDK. + * @property {SDKConfigWatch} [watch] - Settings for file watching features. + * @property {boolean} [sdk-managed-connection-enabled] - + * If the SDK or CLI manages websocket connections for run command executions. + */ + +/** + * Information about the files to watch for specific changes. + * @typedef SDKConfigWatch + * @property {string} filter-regex - Regex pattern for finding filtered files. + * @property {string[]} paths - Specific locations to begin searching for files. + */ + +/** + * Contains available hooks and other configurations available to the SDK. + * @returns {SDKInterface} Information about the hooks currently supported. + */ +export default function getHooks() { + return { + hooks: { + 'get-manifest': 'npx -q --no-install -p @slack/cli-hooks slack-cli-get-manifest', + 'check-update': 'npx -q --no-install -p @slack/cli-hooks slack-cli-check-update', + start: 'npx -q --no-install -p @slack/cli-hooks slack-cli-start', }, - 'sdk-managed-connection-enabled': true, - }, -})); + config: { + watch: { + 'filter-regex': '^manifest\\.json$', + paths: [ + '.', + ], + }, + 'protocol-version': ['default'], + 'sdk-managed-connection-enabled': true, + }, + runtime: 'node', + }; +} diff --git a/packages/cli-hooks/src/get-hooks.spec.js b/packages/cli-hooks/src/get-hooks.spec.js index 7890d47ca..e4c40b354 100644 --- a/packages/cli-hooks/src/get-hooks.spec.js +++ b/packages/cli-hooks/src/get-hooks.spec.js @@ -1,22 +1,18 @@ import { describe, it } from 'mocha'; import assert from 'assert'; -import childProcess from 'child_process'; -import util from 'util'; -const exec = util.promisify(childProcess.exec); +import getHooks from './get-hooks.js'; describe('get-hooks implementation', async () => { it('should return scripts for required hooks', async () => { - const { stdout } = await exec('./src/get-hooks.js'); - const { hooks } = JSON.parse(stdout.trim()); + const { hooks } = getHooks(); assert(hooks['get-manifest'] === 'npx -q --no-install -p @slack/cli-hooks slack-cli-get-manifest'); assert(hooks['check-update'] === 'npx -q --no-install -p @slack/cli-hooks slack-cli-check-update'); assert(hooks.start === 'npx -q --no-install -p @slack/cli-hooks slack-cli-start'); }); it('should return a true managed connection', async () => { - const { stdout } = await exec('./src/get-hooks.js'); - const { config } = JSON.parse(stdout.trim()); + const { config } = getHooks(); assert(config['sdk-managed-connection-enabled']); }); }); diff --git a/packages/cli-hooks/src/get-manifest.js b/packages/cli-hooks/src/get-manifest.js index 3799f0068..37ab01ab4 100755 --- a/packages/cli-hooks/src/get-manifest.js +++ b/packages/cli-hooks/src/get-manifest.js @@ -1,24 +1,26 @@ #!/usr/bin/env node + +import { fileURLToPath } from 'url'; import fs from 'fs'; import path from 'path'; /** - * Implements the get-manifest script hook required by the Slack CLI. - * Prints a well-formatted structure of manifest data to stdout. - * @param {string} cwd - The current working directory of the project. + * Implemention of the get-manifest hook that provides manifest information. + * Printed as a well-formatted structure of project manifest data to stdout. */ -(function _(cwd) { + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const cwd = process.cwd(); const manifest = getManifestData(cwd); - // eslint-disable-next-line no-console - console.log(JSON.stringify(manifest)); -}(process.cwd())); + console.log(JSON.stringify(manifest)); // eslint-disable-line no-console +} /** * Returns parsed manifest data for a project. * @param {string} searchDir - The path to begin searching in. * @returns {object} Parsed values of the project manifest. */ -function getManifestData(searchDir) { +export default function getManifestData(searchDir) { const manifestJSON = readManifestJSONFile(searchDir, 'manifest.json'); if (!manifestJSON) { throw new Error('Failed to find a manifest file in this project'); @@ -38,9 +40,12 @@ function readManifestJSONFile(searchDir, filename) { if (jsonFilePath && fs.existsSync(jsonFilePath)) { return JSON.parse(fs.readFileSync(jsonFilePath, 'utf8')); } - } catch (error) { - console.error(error); // eslint-disable-line no-console - throw new Error('Failed to parse the manifest file for this project'); + } catch (err) { + let message = 'Failed to parse the manifest file for this project'; + if (err instanceof Error) { + message += `\n${err.name}: ${err.message}`; + } + throw new Error(message); } return undefined; } diff --git a/packages/cli-hooks/src/get-manifest.spec.js b/packages/cli-hooks/src/get-manifest.spec.js index d0fa00fb4..3e5e6eaae 100644 --- a/packages/cli-hooks/src/get-manifest.spec.js +++ b/packages/cli-hooks/src/get-manifest.spec.js @@ -1,20 +1,18 @@ import { after, before, describe, it } from 'mocha'; import assert from 'assert'; -import childProcess from 'child_process'; import fs from 'fs'; import path from 'path'; -import util from 'util'; -const exec = util.promisify(childProcess.exec); +import getManifestData from './get-manifest.js'; describe('get-manifest implementation', async () => { describe('missing project manifest file', async () => { it('should error if no manifest.json exists', async () => { try { - await exec('./src/get-manifest.js'); + getManifestData(process.cwd()); } catch (err) { if (err instanceof Error) { - assert(err.message.includes('Error: Failed to find a manifest file in this project')); + assert(err.message.includes('Failed to find a manifest file in this project')); return; } } @@ -23,18 +21,17 @@ describe('get-manifest implementation', async () => { }); describe('broken project manifest file exists', async () => { + const tempDir = path.join(process.cwd(), 'tmp'); + const filePath = path.join(tempDir, 'manifest.json'); + before(() => { - const tempDir = path.join(process.cwd(), 'tmp'); if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir); } - const filePath = path.join(tempDir, 'manifest.json'); fs.writeFileSync(filePath, '{'); }); after(() => { - const tempDir = path.join(process.cwd(), 'tmp'); - const filePath = path.join(tempDir, 'manifest.json'); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } @@ -45,13 +42,13 @@ describe('get-manifest implementation', async () => { it('should error for invalid manifest.json', async () => { try { - await exec('./src/get-manifest.js'); + getManifestData(process.cwd()); } catch (err) { if (err instanceof Error) { const nodeV18Error = 'SyntaxError: Unexpected end of JSON input'; const nodeV20Error = "SyntaxError: Expected property name or '}' in JSON at position 1"; assert(err.message.includes(nodeV20Error) || err.message.includes(nodeV18Error)); - assert(err.message.includes('Error: Failed to parse the manifest file for this project')); + assert(err.message.includes('Failed to parse the manifest file for this project')); return; } } @@ -60,6 +57,8 @@ describe('get-manifest implementation', async () => { }); describe('contains project manifest file', async () => { + const tempDir = path.join(process.cwd(), 'tmp'); + const filePath = path.join(tempDir, 'manifest.json'); const manifest = { display_information: { name: 'Example app', @@ -78,17 +77,13 @@ describe('get-manifest implementation', async () => { }; before(() => { - const tempDir = path.join(process.cwd(), 'tmp'); if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir); } - const filePath = path.join(tempDir, 'manifest.json'); fs.writeFileSync(filePath, JSON.stringify(manifest, null, 2)); }); after(() => { - const tempDir = path.join(process.cwd(), 'tmp'); - const filePath = path.join(tempDir, 'manifest.json'); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } @@ -99,8 +94,7 @@ describe('get-manifest implementation', async () => { it('should return existing manifest values', async () => { try { - const { stdout } = await exec('./src/get-manifest.js'); - const parsedManifest = JSON.parse(stdout); + const parsedManifest = getManifestData(process.cwd()); assert.deepEqual(manifest, parsedManifest); } catch (err) { console.error(err); // eslint-disable-line no-console diff --git a/packages/cli-hooks/src/start.js b/packages/cli-hooks/src/start.js index 39ee904e3..147628ea8 100755 --- a/packages/cli-hooks/src/start.js +++ b/packages/cli-hooks/src/start.js @@ -1,27 +1,35 @@ #!/usr/bin/env node -import { spawn } from 'child_process'; + +import { fileURLToPath } from 'url'; +import childProcess from 'child_process'; import path from 'path'; import fs from 'fs'; -const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf-8')); +/** + * Implementation of the start hook that begins a new process to run the app. + * The child processes will continue until exited or interrupted by the caller. + */ + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + start(process.cwd()); +} /** * Start hook implementation that verifies and runs an app in Socket Mode. * @param {string} cwd - The current working directory of the project. - * @param {string | undefined} customPath - An optional path for the app. */ -(function _(cwd, customPath) { +export default function start(cwd) { // TODO - Format so that its less miss-able in output console.log('Preparing local run in developer mode (Socket Mode)'); // eslint-disable-line no-console validateEnvironment(); - // Tries the provided path, then package.json main, then defaults to app.js + const customPath = process.env.SLACK_CLI_CUSTOM_FILE_PATH; + const pkgJSONMain = getPackageJSONMain(cwd); const pkgJSONDefault = 'app.js'; - const fullPath = path.resolve(cwd, customPath || (pkgJSONMain || pkgJSONDefault)); + const fullPath = path.resolve(cwd, customPath || pkgJSONMain || pkgJSONDefault); console.log(fullPath); // eslint-disable-line no-console - // Kick off a subprocess to run the app in development mode - const app = spawn('node', [`${fullPath}`]); + const app = childProcess.spawn('node', [`${fullPath}`]); app.stdout.setEncoding('utf-8'); app.stdout.on('data', (data) => { process.stdout.write(data); @@ -29,20 +37,34 @@ const { main: pkgJSONMain } = JSON.parse(fs.readFileSync('./package.json', 'utf- app.stderr.on('data', (data) => { process.stderr.write(data); }); - app.on('close', (code) => { console.log(`Local run exited with code ${code}`); // eslint-disable-line no-console }); -}(process.cwd(), process.env.SLACK_CLI_CUSTOM_FILE_PATH)); +} + +/** + * Gathers the main value from the package.json for the project if present. + * @param {string} cwd - The current working directory of the project. + * @returns {string | undefined} - The main script to run for the project. + */ +function getPackageJSONMain(cwd) { + try { + const packageJSONPath = path.join(cwd, 'package.json'); + const { main } = JSON.parse(fs.readFileSync(packageJSONPath, 'utf-8')); + return main; + } catch { + return undefined; + } +} /** * Confirms environment variables are prepared by the CLI. */ function validateEnvironment() { if (!process.env.SLACK_CLI_XOXB) { - throw new Error('Missing local run bot token. Please see slack-cli maintainers to troubleshoot.'); + throw new Error('Missing local run bot token. Please see Slack CLI maintainers to troubleshoot.'); } if (!process.env.SLACK_CLI_XAPP) { - throw new Error('Missing local run app token. Please see slack-cli maintainers to troubleshoot'); + throw new Error('Missing local run app token. Please see Slack CLI maintainers to troubleshoot'); } } diff --git a/packages/cli-hooks/src/start.spec.js b/packages/cli-hooks/src/start.spec.js index e287219c0..7d9df284e 100644 --- a/packages/cli-hooks/src/start.spec.js +++ b/packages/cli-hooks/src/start.spec.js @@ -1,151 +1,143 @@ -import { after, afterEach, before, describe, it } from 'mocha'; +import { after, afterEach, before, beforeEach, describe, it } from 'mocha'; import assert from 'assert'; import childProcess from 'child_process'; import fs from 'fs'; import path from 'path'; -import util from 'util'; +import sinon from 'sinon'; -const exec = util.promisify(childProcess.exec); +import start from './start.js'; /** - * Mock app information for packages of the project. + * @typedef MockStreams + * @property {sinon.SinonStub} on - The istener function for this event stream. + * @property {() => void} [setEncoding] - Character encoding of the output bytes. */ -const mainPackageJSON = { name: 'Example application', main: 'start.js' }; -const defaultPackageJSON = { name: 'Example application' }; /** - * Mock a super simple app script to verify outputs. + * @typedef MockSpawnProcess + * @property {MockStreams} stdout - Output logged to standard output streams. + * @property {MockStreams} stderr - Output logged to standard error streams. + * @property {sinon.SinonStub} on - A fallback event to mock the spawn closure. */ -const appScript = `\ -console.log("coffee"); -console.error("sips"); -`; describe('start implementation', async () => { - describe('begins the main app process', async () => { - before(() => { + describe('begins the app process', async () => { + /** @type {sinon.SinonStub} */ + let consoleLogStub; + /** @type {sinon.SinonStub} */ + let stdoutWriteStub; + /** @type {sinon.SinonStub} */ + let stderrWriteStub; + /** @type {MockSpawnProcess} */ + let mockSpawnProcess; + /** @type {sinon.SinonStub} */ + let spawnStub; + + beforeEach(() => { + consoleLogStub = sinon.stub(console, 'log'); + stdoutWriteStub = sinon.stub(process.stdout, 'write'); + stderrWriteStub = sinon.stub(process.stderr, 'write'); + mockSpawnProcess = { + stdout: { on: sinon.stub(), setEncoding: () => { } }, + stderr: { on: sinon.stub() }, + on: sinon.stub(), + }; + spawnStub = sinon.stub(childProcess, 'spawn').returns(/** @type {any} */(mockSpawnProcess)); process.env.SLACK_CLI_XAPP = 'xapp-example'; process.env.SLACK_CLI_XOXB = 'xoxb-example'; - const tempDir = path.join(process.cwd(), 'tmp'); - if (!fs.existsSync(tempDir)) { - fs.mkdirSync(tempDir); - } - const appFilePath = path.join(tempDir, 'start.js'); - fs.writeFileSync(appFilePath, appScript); - const packageJSONFilePath = path.join(tempDir, 'package.json'); - fs.writeFileSync(packageJSONFilePath, JSON.stringify(mainPackageJSON, null, 2)); }); - after(() => { + afterEach(() => { + sinon.restore(); delete process.env.SLACK_CLI_XOXB; delete process.env.SLACK_CLI_XAPP; - const tempDir = path.join(process.cwd(), 'tmp'); - const appFilePath = path.join(tempDir, 'start.js'); - if (fs.existsSync(appFilePath)) { - fs.unlinkSync(appFilePath); - } - const packageJSONFilePath = path.join(tempDir, 'package.json'); - if (fs.existsSync(packageJSONFilePath)) { - fs.unlinkSync(packageJSONFilePath); - } - if (fs.existsSync(tempDir)) { - fs.rmSync(tempDir, { recursive: true }); - } }); - it('writes output from the main script', async () => { - const { stdout, stderr } = await exec('../src/start.js', { cwd: './tmp' }); - assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); - assert(stdout.includes('coffee')); - assert(stderr.includes('sips')); - assert(stdout.includes('Local run exited with code 0')); - }); - }); - - describe('begins the default app process', async () => { - before(() => { - process.env.SLACK_CLI_XAPP = 'xapp-example'; - process.env.SLACK_CLI_XOXB = 'xoxb-example'; + describe('runs the package main path', async () => { const tempDir = path.join(process.cwd(), 'tmp'); - if (!fs.existsSync(tempDir)) { - fs.mkdirSync(tempDir); - } - const appFilePath = path.join(tempDir, 'app.js'); - fs.writeFileSync(appFilePath, appScript); const packageJSONFilePath = path.join(tempDir, 'package.json'); - fs.writeFileSync(packageJSONFilePath, JSON.stringify(defaultPackageJSON, null, 2)); - }); - after(() => { - delete process.env.SLACK_CLI_XOXB; - delete process.env.SLACK_CLI_XAPP; - const tempDir = path.join(process.cwd(), 'tmp'); - const filePath = path.join(tempDir, 'app.js'); - if (fs.existsSync(filePath)) { - fs.unlinkSync(filePath); - } - const packageJSONFilePath = path.join(tempDir, 'package.json'); - if (fs.existsSync(packageJSONFilePath)) { - fs.unlinkSync(packageJSONFilePath); - } - if (fs.existsSync(tempDir)) { - fs.rmSync(tempDir, { recursive: true }); - } - }); + before(() => { + const mainPackageJSON = { name: 'Example application', main: 'start.js' }; + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + fs.writeFileSync(packageJSONFilePath, JSON.stringify(mainPackageJSON, null, 2)); + }); - it('writes output from the default script', async () => { - const { stdout, stderr } = await exec('../src/start.js', { cwd: './tmp' }); - assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); - assert(stdout.includes('coffee')); - assert(stderr.includes('sips')); - assert(stdout.includes('Local run exited with code 0')); - }); - }); + after(() => { + if (fs.existsSync(packageJSONFilePath)) { + fs.unlinkSync(packageJSONFilePath); + } + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true }); + } + }); - describe('begins the custom app process', async () => { - before(() => { - process.env.SLACK_CLI_XAPP = 'xapp-example'; - process.env.SLACK_CLI_XOXB = 'xoxb-example'; - process.env.SLACK_CLI_CUSTOM_FILE_PATH = 'application.js'; - const tempDir = path.join(process.cwd(), 'tmp'); - if (!fs.existsSync(tempDir)) { - fs.mkdirSync(tempDir); - } - const appFilePath = path.join(tempDir, 'application.js'); - fs.writeFileSync(appFilePath, appScript); - const packageJSONFilePath = path.join(tempDir, 'package.json'); - fs.writeFileSync(packageJSONFilePath, JSON.stringify(mainPackageJSON, null, 2)); + it('writes output from the main script', () => { + start('./tmp'); + mockSpawnProcess.stdout.on.callArgWith(1, 'message'); + mockSpawnProcess.stderr.on.callArgWith(1, 'warning'); + mockSpawnProcess.on.callArgWith(1, 0); + + assert.ok(consoleLogStub.calledWith('Preparing local run in developer mode (Socket Mode)')); + assert.ok(spawnStub.called); + assert.ok(spawnStub.calledWith('node', [path.resolve('tmp', 'start.js')])); + assert.ok(stdoutWriteStub.calledWith('message')); + assert.ok(stderrWriteStub.calledWith('warning')); + assert.ok(consoleLogStub.calledWith('Local run exited with code 0')); + }); }); - after(() => { - delete process.env.SLACK_CLI_XOXB; - delete process.env.SLACK_CLI_XAPP; - delete process.env.SLACK_CLI_CUSTOM_FILE_PATH; - const tempDir = path.join(process.cwd(), 'tmp'); - const appFilePath = path.join(tempDir, 'application.js'); - if (fs.existsSync(appFilePath)) { - fs.unlinkSync(appFilePath); - } - const packageJSONFilePath = path.join(tempDir, 'package.json'); - if (fs.existsSync(packageJSONFilePath)) { - fs.unlinkSync(packageJSONFilePath); - } - if (fs.existsSync(tempDir)) { - fs.rmSync(tempDir, { recursive: true }); - } + describe('runs the default app path', async () => { + it('writes output from the default script', async () => { + start('./tmp'); + mockSpawnProcess.stdout.on.callArgWith(1, 'defaults'); + mockSpawnProcess.stderr.on.callArgWith(1, 'watch out'); + mockSpawnProcess.on.callArgWith(1, 2); + + assert.ok(consoleLogStub.calledWith('Preparing local run in developer mode (Socket Mode)')); + assert.ok(spawnStub.called); + assert.ok(spawnStub.calledWith('node', [path.resolve('tmp', 'app.js')])); + assert.ok(stdoutWriteStub.calledWith('defaults')); + assert.ok(stderrWriteStub.calledWith('watch out')); + assert.ok(consoleLogStub.calledWith('Local run exited with code 2')); + }); }); - it('writes output from the custom script', async () => { - const { stdout, stderr } = await exec('../src/start.js', { cwd: './tmp' }); - assert(stdout.includes('Preparing local run in developer mode (Socket Mode)')); - assert(stdout.includes('coffee')); - assert(stderr.includes('sips')); - assert(stdout.includes('Local run exited with code 0')); + describe('runs the custom app path', async () => { + before(() => { + process.env.SLACK_CLI_CUSTOM_FILE_PATH = 'application.js'; + }); + + after(() => { + delete process.env.SLACK_CLI_CUSTOM_FILE_PATH; + }); + + it('writes output from the custom script', async () => { + start('./'); + mockSpawnProcess.stdout.on.callArgWith(1, 'startled'); + mockSpawnProcess.stderr.on.callArgWith(1, 'erroneous'); + mockSpawnProcess.on.callArgWith(1, 4); + + assert.ok(consoleLogStub.calledWith('Preparing local run in developer mode (Socket Mode)')); + assert.ok(spawnStub.called); + assert.ok(spawnStub.calledWith('node', [path.resolve('application.js')])); + assert.ok(stdoutWriteStub.calledWith('startled')); + assert.ok(stderrWriteStub.calledWith('erroneous')); + assert.ok(consoleLogStub.calledWith('Local run exited with code 4')); + }); }); }); - describe('withot valid tokens', async () => { + describe('without valid tokens', async () => { + beforeEach(() => { + sinon.stub(console, 'log'); + delete process.env.SLACK_CLI_XOXB; + delete process.env.SLACK_CLI_XAPP; + }); afterEach(() => { + sinon.restore(); delete process.env.SLACK_CLI_XOXB; delete process.env.SLACK_CLI_XAPP; }); @@ -153,10 +145,10 @@ describe('start implementation', async () => { it('should error without a bot token', async () => { try { process.env.SLACK_CLI_XAPP = 'xapp-example'; - await exec('./src/start.js'); + start('./'); } catch (err) { if (err instanceof Error) { - assert(err.message.includes('Error: Missing local run bot token')); + assert(err.message.includes('Missing local run bot token')); return; } } @@ -166,10 +158,10 @@ describe('start implementation', async () => { it('should error without an app token', async () => { try { process.env.SLACK_CLI_XOXB = 'xoxb-example'; - await exec('./src/start.js'); + start('./'); } catch (err) { if (err instanceof Error) { - assert(err.message.includes('Error: Missing local run app token')); + assert(err.message.includes('Missing local run app token')); return; } } From a4ba93ec8f0c81c0464f489781c43e701eabd078 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 01:52:22 -0800 Subject: [PATCH 22/45] style: remove leftover jsdoc from a testing iteration --- packages/cli-hooks/src/check-update.spec.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/cli-hooks/src/check-update.spec.js b/packages/cli-hooks/src/check-update.spec.js index db8a08ce0..7c485f3a5 100644 --- a/packages/cli-hooks/src/check-update.spec.js +++ b/packages/cli-hooks/src/check-update.spec.js @@ -48,16 +48,11 @@ function mockNPM(command) { throw new Error('Unknown NPM command mocked'); } -/** - * @typedef MockExecProcess - * @property {string} stdout - Output logged to standard output streams. - * @property {string} stderr - Output logged to standard error streams. - */ - describe('check-update implementation', async () => { describe('collects recent package versions', async () => { const tempDir = path.join(process.cwd(), 'tmp'); const packageJSONFilePath = path.join(tempDir, 'package.json'); + before(() => { sinon.stub(util, 'promisify') .returns((/** @type {string} */ command) => { From 287b21b01eb984569303b3edaa413dc1fedad69c Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 01:56:23 -0800 Subject: [PATCH 23/45] feat: adapt the message boundaries protocol implementation --- packages/cli-hooks/package.json | 4 + packages/cli-hooks/src/get-hooks.js | 2 +- packages/cli-hooks/src/get-hooks.spec.js | 5 + packages/cli-hooks/src/protocol.spec.js | 81 +++++++++++++++ packages/cli-hooks/src/protocols.js | 119 +++++++++++++++++++++++ 5 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 packages/cli-hooks/src/protocol.spec.js create mode 100644 packages/cli-hooks/src/protocols.js diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index da53c5529..96ac4def2 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -46,7 +46,11 @@ "slack-cli-check-update": "src/check-update.js", "slack-cli-start": "src/start.js" }, + "dependencies": { + "minimist": "^1.2.8" + }, "devDependencies": { + "@types/minimist": "^1.2.5", "@types/mocha": "^10.0.6", "@types/node": "^20.10.8", "@types/sinon": "^17.0.3", diff --git a/packages/cli-hooks/src/get-hooks.js b/packages/cli-hooks/src/get-hooks.js index e2abb8e74..fb2183cb2 100755 --- a/packages/cli-hooks/src/get-hooks.js +++ b/packages/cli-hooks/src/get-hooks.js @@ -53,7 +53,7 @@ export default function getHooks() { '.', ], }, - 'protocol-version': ['default'], + 'protocol-version': ['message-boundaries', 'default'], 'sdk-managed-connection-enabled': true, }, runtime: 'node', diff --git a/packages/cli-hooks/src/get-hooks.spec.js b/packages/cli-hooks/src/get-hooks.spec.js index e4c40b354..f7be43004 100644 --- a/packages/cli-hooks/src/get-hooks.spec.js +++ b/packages/cli-hooks/src/get-hooks.spec.js @@ -11,6 +11,11 @@ describe('get-hooks implementation', async () => { assert(hooks.start === 'npx -q --no-install -p @slack/cli-hooks slack-cli-start'); }); + it('should return every protocol version', async () => { + const { config } = getHooks(); + assert.deepEqual(config['protocol-version'], ['message-boundaries', 'default']); + }); + it('should return a true managed connection', async () => { const { config } = getHooks(); assert(config['sdk-managed-connection-enabled']); diff --git a/packages/cli-hooks/src/protocol.spec.js b/packages/cli-hooks/src/protocol.spec.js new file mode 100644 index 000000000..8bbbfd305 --- /dev/null +++ b/packages/cli-hooks/src/protocol.spec.js @@ -0,0 +1,81 @@ +/* eslint-disable no-console */ + +import { afterEach, beforeEach, describe, it } from 'mocha'; +import assert from 'assert'; +import sinon from 'sinon'; + +import { + BaseProtocol, + MessageBoundaryProtocol, + getProtocolInterface, +} from './protocols.js'; + +describe('protocol implementations', () => { + describe('default protocol', () => { + it('stubs logging methods with a manifest flag', () => { + const protocol = BaseProtocol(['--manifest']); + assert.notEqual(protocol.log, console.log); + assert.notEqual(protocol.error, console.error); + assert.notEqual(protocol.warn, console.warn); + assert.equal(protocol.respond, console.log); + }); + + it('uses console log methods without a manifest', () => { + const protocol = BaseProtocol(['--flag']); + assert.equal(protocol.log, console.log); + assert.equal(protocol.error, console.log); + assert.equal(protocol.warn, console.log); + assert.equal(protocol.respond, console.log); + }); + }); + + describe('message boundary protocol', () => { + /** @type {sinon.SinonStub} */ + let consoleLogStub; + + beforeEach(() => { + consoleLogStub = sinon.stub(console, 'log'); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('errors if no boundary is specified', () => { + assert.throws(() => { + MessageBoundaryProtocol([]); + }); + }); + + it('uses the corresponding console methods', () => { + const protocol = MessageBoundaryProtocol(['--boundary=line']); + assert.equal(protocol.log, console.log); + assert.equal(protocol.error, console.error); + assert.equal(protocol.warn, console.warn); + }); + + it('surrounds hook responses with the boundary', () => { + const protocol = MessageBoundaryProtocol(['--boundary=x08o']); + protocol.respond('greetings'); + consoleLogStub.calledWith('x08ogreetingsx08o'); + }); + }); + + describe('get protocol interface', () => { + it('returns the base protocol by default', () => { + const protocol = getProtocolInterface([]).name; + assert.equal(protocol, 'default'); + }); + + it('returns the base protocol if unrecognized', () => { + const protocol = getProtocolInterface(['--protocol=cryptics']).name; + assert.equal(protocol, 'default'); + }); + + it('returns the specified message boundary protocol', () => { + const args = ['--protocol=message-boundaries', '--boundary=racecar']; + const protocol = getProtocolInterface(args).name; + assert.equal(protocol, 'message-boundaries'); + }); + }); +}); diff --git a/packages/cli-hooks/src/protocols.js b/packages/cli-hooks/src/protocols.js new file mode 100644 index 000000000..c87eda2ec --- /dev/null +++ b/packages/cli-hooks/src/protocols.js @@ -0,0 +1,119 @@ +import minimist from 'minimist'; + +/** + * An interface encapsulating a specific set of communication rules that the + * SDK and the CLI both implement. + * @typedef {object} Protocol + * @property {string} name - + * Label representing the name of the protocol as expected by the Slack CLI. + * @property {typeof console.log} log - + * Logging utility to surface diagnostic info from the SDK or username code. + * @property {typeof console.error} error - + * Logging utility to surface errors from the SDK or username code. + * @property {typeof console.warn} warn - + * Logging utility to surface warnings from the SDK or username code. + * @property {(data: string) => void} respond - + * Utility method for responding to hook invocations with stringified JSON. + * @property {() => string[]} [getCLIFlags] - + * Retrieves all command-line flags related to the protocol implementation. + * Most useful when child processes are being spawned by the SDK. + * @property {() => void} [install] - + * Optional instructions for the protocol to install itself into the runtime. + * Similar to stubbing functionality in mocking or testing setup utilties. + * Ensures that the protocol expectations are met by userland and SDK code. + * @property {() => void} [uninstall] - + * Optional instructions for the protocol to remove itself from the runtime. + */ + +const DEFAULT_PROTOCOL = 'default'; +const MSG_BOUNDARY_PROTOCOL = 'message-boundaries'; +const SUPPORTED_NAMED_PROTOCOLS = [MSG_BOUNDARY_PROTOCOL]; + +/** + * The baseline CLI-SDK protocol. All responses in this protocol go to stdout. + * The CLI combines both stdout and stderr to interpret the hook response. + * This simplistic protocol has inherent limitation: no logging diagnostics! + * @param {string[]} args - Command-line arguments passed to this process. + * @returns {Protocol} Specified communication rules for the SDK to follow. + */ +export function BaseProtocol(args) { + const { manifest: manifestOnly = false } = parseArgs(args); + + // If the particular hook invocation is requesting manifest generation we + // ensure any logging is a no-op to prevent littering stdout with logging + // and confusing the CLI's manifest JSON payload parsing. + const loggerMethod = manifestOnly ? () => { } : console.log; // eslint-disable-line no-console + return { + name: DEFAULT_PROTOCOL, + log: loggerMethod, + error: loggerMethod, + warn: loggerMethod, + respond: console.log, // eslint-disable-line no-console + }; +} + +/** + * Protocol implementation that uses both stdout and stderr for logs and alerts, + * but also uses message boundaries to differentiate between application created + * diagnostic information and hook responses. + * @param {string[]} args - Command-line arguments passed to this process. + * @returns {Protocol} Specified communication rules for the SDK to follow. + */ +export function MessageBoundaryProtocol(args) { + const { boundary } = parseArgs(args); + if (!boundary) throw new Error('no boundary argument provided!'); + const protocol = { + name: MSG_BOUNDARY_PROTOCOL, + log: console.log, // eslint-disable-line no-console + error: console.error, // eslint-disable-line no-console + warn: console.warn, // eslint-disable-line no-console + respond: (/** @type {any} */ data) => { + console.log(boundary + data + boundary); // eslint-disable-line no-console + }, + getCLIFlags: () => [ + `--protocol=${MSG_BOUNDARY_PROTOCOL}`, + `--boundary=${boundary}`, + ], + }; + return protocol; +} + +// A map of protocol names to protocol implementations +const PROTOCOL_MAP = { + [SUPPORTED_NAMED_PROTOCOLS[0]]: MessageBoundaryProtocol, +}; + +/** + * Determines the protocol interface to use when communicating with the CLI. + * Based on the arguments provided by the CLI to the SDK hook process. + * @param {string[]} args - Command-line flags and arguments passed to the hook. + * @returns {Protocol} The interface to follow when messaging to the CLI. + */ +export function getProtocolInterface(args) { + const { protocol: protocolRequestedByCLI } = parseArgs(args); + if (protocolRequestedByCLI) { + if (SUPPORTED_NAMED_PROTOCOLS.includes(protocolRequestedByCLI)) { + const iface = PROTOCOL_MAP[protocolRequestedByCLI]; + // Allow support for protocol implementations to either be: + // - a function, using arguments passed to this process to + // dynamically instantiate a Protocol interface + // - an object implementing the Protocol interface directly + if (typeof iface === 'function') { + return iface(args); + } + return iface; + } + } + + // If protocol negotiation fails for any reason, return the base protocol + return BaseProtocol(args); +} + +/** + * Parses command line arguments into a consumable object. + * @param {string[]} argv - Command line values. + * @returns {import("minimist").ParsedArgs} The object of parsed arguments. + */ +function parseArgs(argv) { + return minimist(argv); +} From c96858b5a6aa74cf424053f93f53ebeb55255cf9 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 20:46:03 -0800 Subject: [PATCH 24/45] feat: remove upgrade checks for the deno sdk --- packages/cli-hooks/src/check-update.js | 6 ------ packages/cli-hooks/src/check-update.spec.js | 15 --------------- 2 files changed, 21 deletions(-) diff --git a/packages/cli-hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js index cadd2f199..23f0fe0c5 100755 --- a/packages/cli-hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -7,7 +7,6 @@ import util from 'util'; const SLACK_BOLT_SDK = '@slack/bolt'; const SLACK_CLI_HOOKS = '@slack/cli-hooks'; -const SLACK_DENO_SDK = '@slack/deno-slack-sdk'; /** * Implementation of the check-update hook that finds available SDK updates. @@ -82,9 +81,6 @@ async function getProjectDependencies(cwd) { if (projectDependencies.dependencies[SLACK_BOLT_SDK]) { versionMap[SLACK_BOLT_SDK] = await collectVersionInfo(SLACK_BOLT_SDK); } - if (projectDependencies.dependencies[SLACK_DENO_SDK]) { - versionMap[SLACK_DENO_SDK] = await collectVersionInfo(SLACK_DENO_SDK); - } if (projectDependencies.dependencies[SLACK_CLI_HOOKS]) { versionMap[SLACK_CLI_HOOKS] = await collectVersionInfo(SLACK_CLI_HOOKS); } @@ -213,8 +209,6 @@ async function fetchLatestPackageVersion(packageName) { function getReleaseNotesUrl(packageName, latestVersion) { if (packageName === SLACK_BOLT_SDK) { return `https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@${latestVersion}`; - } if (packageName === SLACK_DENO_SDK) { - return `https://github.com/slackapi/deno-slack-sdk/releases/tag/${latestVersion}`; } if (packageName === SLACK_CLI_HOOKS) { return `https://github.com/slackapi/node-slack-sdk/releases/tag/@slack/cli-hooks@${latestVersion}`; } diff --git a/packages/cli-hooks/src/check-update.spec.js b/packages/cli-hooks/src/check-update.spec.js index 7c485f3a5..baf182186 100644 --- a/packages/cli-hooks/src/check-update.spec.js +++ b/packages/cli-hooks/src/check-update.spec.js @@ -18,7 +18,6 @@ const packageJSON = { name: 'Example application', dependencies: { '@slack/bolt': '^3.0.0', - '@slack/deno-slack-sdk': '^2.0.0', }, devDependencies: { '@slack/cli-hooks': '^0.0.1', @@ -33,15 +32,11 @@ const packageJSON = { function mockNPM(command) { if (command === 'npm info @slack/bolt version --tag latest') { return '3.1.4'; - } if (command === 'npm info @slack/deno-slack-sdk version --tag latest') { - return '2.0.0'; } if (command === 'npm info @slack/cli-hooks version --tag latest') { return '1.0.1'; } if (command === 'npm list @slack/bolt --depth=0 --json') { return '{"dependencies":{"@slack/bolt":{"version":"3.0.0"}}}'; - } if (command === 'npm list @slack/deno-slack-sdk --depth=0 --json') { - return '{"dependencies":{"@slack/deno-slack-sdk":{"version":"2.0.0"}}}'; } if (command === 'npm list @slack/cli-hooks --depth=0 --json') { return '{"dependencies":{"@slack/cli-hooks":{"version":"0.0.1"}}}'; } @@ -94,16 +89,6 @@ describe('check-update implementation', async () => { breaking: false, url: 'https://github.com/slackapi/bolt-js/releases/tag/@slack/bolt@3.1.4', }, - { - name: '@slack/deno-slack-sdk', - current: '2.0.0', - latest: '2.0.0', - error: undefined, - update: false, - message: undefined, - breaking: false, - url: undefined, - }, { name: '@slack/cli-hooks', current: '0.0.1', From af8c9a3f22588941b653aa9ac3448e82f2959d4e Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 21:07:58 -0800 Subject: [PATCH 25/45] feat: compare package versions with the semver package --- packages/cli-hooks/package.json | 3 ++- packages/cli-hooks/src/check-update.js | 22 +++++---------------- packages/cli-hooks/src/check-update.spec.js | 8 ++++++++ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 96ac4def2..95a0eede4 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -47,7 +47,8 @@ "slack-cli-start": "src/start.js" }, "dependencies": { - "minimist": "^1.2.8" + "minimist": "^1.2.8", + "semver": "^7.5.4" }, "devDependencies": { "@types/minimist": "^1.2.5", diff --git a/packages/cli-hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js index 23f0fe0c5..121a1bff8 100755 --- a/packages/cli-hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -1,5 +1,6 @@ #!/usr/bin/env node +import { clean, gt, major } from 'semver'; import { fileURLToPath } from 'url'; import childProcess from 'child_process'; import fs from 'fs'; @@ -222,21 +223,10 @@ function getReleaseNotesUrl(packageName, latestVersion) { * @returns {boolean} If the update will result in a breaking change. */ export function hasAvailableUpdates(current, latest) { - if (!current || !latest) { + if (!current || !latest || !clean(current) || !clean(latest)) { return false; } - const [currMajor, currMinor, currPatch] = current - .split('.') - .map((val) => Number(val)); - const [targetMajor, targetMinor, targetPatch] = latest - .split('.') - .map((val) => Number(val)); - if (targetMajor !== currMajor) { - return targetMajor > currMajor; - } if (targetMinor !== currMinor) { - return targetMinor > currMinor; - } - return targetPatch > currPatch; + return gt(latest, current); } /** @@ -246,12 +236,10 @@ export function hasAvailableUpdates(current, latest) { * @returns {boolean} If the update will result in a breaking change. */ export function hasBreakingChange(current, latest) { - if (!current || !latest) { + if (!current || !latest || !clean(current) || !clean(latest)) { return false; } - const currMajor = current.split('.')[0]; - const latestMajor = latest.split('.')[0]; - return +latestMajor - +currMajor >= 1; + return major(latest) > major(current); } /** diff --git a/packages/cli-hooks/src/check-update.spec.js b/packages/cli-hooks/src/check-update.spec.js index baf182186..217a17bfc 100644 --- a/packages/cli-hooks/src/check-update.spec.js +++ b/packages/cli-hooks/src/check-update.spec.js @@ -119,6 +119,8 @@ describe('check-update implementation', async () => { assert(hasAvailableUpdates('1.0.0', '1.1.1')); assert(hasAvailableUpdates('1.0.0', '2.0.0')); assert(hasAvailableUpdates('0.0.2', '0.0.13')); + assert(hasAvailableUpdates('0.0.2-rc.0', '0.0.2-rc.1')); + assert(hasAvailableUpdates('0.0.3-rc.2', '0.0.3')); assert(!hasAvailableUpdates('0.0.1', '0.0.1')); assert(!hasAvailableUpdates('0.1.0', '0.1.0')); assert(!hasAvailableUpdates('0.1.1', '0.1.1')); @@ -126,6 +128,7 @@ describe('check-update implementation', async () => { assert(!hasAvailableUpdates('1.0.1', '1.0.1')); assert(!hasAvailableUpdates('1.1.1', '1.1.1')); assert(!hasAvailableUpdates(undefined, undefined)); + assert(!hasAvailableUpdates(undefined, '1.0.0')); assert(!hasAvailableUpdates('1.0.0', undefined)); assert(!hasAvailableUpdates('2.0.0', '1.0.0')); assert(!hasAvailableUpdates('2.0.0', '0.1.0')); @@ -143,6 +146,8 @@ describe('check-update implementation', async () => { assert(!hasAvailableUpdates('0.2.0', '0.1.3')); assert(!hasAvailableUpdates('0.0.2', '0.0.1')); assert(!hasAvailableUpdates('0.0.20', '0.0.13')); + assert(!hasAvailableUpdates('0.0.2-rc.0', '0.0.2-rc.0')); + assert(!hasAvailableUpdates('0.0.2', '0.0.2-rc.4')); }); it('should return if the update is major', () => { @@ -153,6 +158,9 @@ describe('check-update implementation', async () => { assert(!hasBreakingChange('1.0.0', '1.0.0')); assert(!hasBreakingChange('1.0.0', '1.0.1')); assert(!hasBreakingChange('1.0.0', '1.2.3')); + assert(!hasBreakingChange(undefined, '1.0.0')); + assert(!hasBreakingChange('1.0.0', undefined)); + assert(!hasBreakingChange(undefined, undefined)); }); }); From a4c2cc0e75b8eb3e7970baf2249b2b5383bb2b6d Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 21:43:46 -0800 Subject: [PATCH 26/45] docs: note steps for troubleshooting global installations --- packages/cli-hooks/README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/cli-hooks/README.md b/packages/cli-hooks/README.md index 13a270e7c..a671b5e53 100644 --- a/packages/cli-hooks/README.md +++ b/packages/cli-hooks/README.md @@ -42,11 +42,10 @@ that are available in the Slack CLI. By default, `get-hooks` retrieves all of the [supported hooks][supported] and their corresponding scripts as defined in this package. -The CLI will always use the version of the `@slack/cli-hooks` specified in the -project's `package.json`. - -These scripts are automatically added to the `./node_modules/.bin` directory of -a project when this package is installed. +The CLI will try to use the version of the `@slack/cli-hooks` specified in your +application's `package.json`. The hooks in this package are automatically added +to the `./node_modules/.bin` directory of your application when this package is +installed. ### Supported Hooks @@ -80,6 +79,23 @@ Below is an example `slack.json` file that overrides the default `start` hook: } ``` +### Troubleshooting + +Sometimes the hook scripts are installed globally and might not be automatically +updated. To determine the source of these scripts, check the `node_modules/.bin` +directory of your project then run the following command: + +```sh +$ which npx slack-cli-get-hooks # macOS / Linux +``` + +```cmd +C:\> where.exe npx slack-cli-get-hooks # Windows +``` + +These hooks can be safely removed and reinstalled at your application directory +to ensure you're using the correct version for your project. + ## Getting help If you get stuck, we're here to help. The following are the best ways to get From 0e5cf6089d57142887b7ede61c1d93c015bfd87f Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 21:50:25 -0800 Subject: [PATCH 27/45] chore: include the mit license with this package --- packages/cli-hooks/LICENSE | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 packages/cli-hooks/LICENSE diff --git a/packages/cli-hooks/LICENSE b/packages/cli-hooks/LICENSE new file mode 100644 index 000000000..e0e9e304f --- /dev/null +++ b/packages/cli-hooks/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024- Slack Technologies, LLC + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 953588b7e12da7e13fcd22b9acae70b7fc815c63 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 21:51:19 -0800 Subject: [PATCH 28/45] chore: bump the package patch version --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 95a0eede4..fdb22a903 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.8", + "version": "0.0.9", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From 143075af766aceb344bbac0da73324a1f75fd290 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 22:10:16 -0800 Subject: [PATCH 29/45] fix: include semver types for the typescript typechecker --- packages/cli-hooks/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index fdb22a903..35cd7455d 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -54,6 +54,7 @@ "@types/minimist": "^1.2.5", "@types/mocha": "^10.0.6", "@types/node": "^20.10.8", + "@types/semver": "^7.5.6", "@types/sinon": "^17.0.3", "c8": "^9.0.0", "eslint-config-airbnb-base": "^15.0.0", From 3587643026304361a5e99613816ce602f3c1b7c5 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 22:11:14 -0800 Subject: [PATCH 30/45] fix: follow script symbolic links to the actual file path --- packages/cli-hooks/src/check-update.js | 2 +- packages/cli-hooks/src/get-hooks.js | 3 ++- packages/cli-hooks/src/get-manifest.js | 2 +- packages/cli-hooks/src/start.js | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/cli-hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js index 121a1bff8..0167457f6 100755 --- a/packages/cli-hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -14,7 +14,7 @@ const SLACK_CLI_HOOKS = '@slack/cli-hooks'; * Prints an object detailing information on Slack dependencies for the CLI. */ -if (process.argv[1] === fileURLToPath(import.meta.url)) { +if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { checkForSDKUpdates(process.cwd()).then(JSON.stringify).then(console.log); // eslint-disable-line no-console } diff --git a/packages/cli-hooks/src/get-hooks.js b/packages/cli-hooks/src/get-hooks.js index fb2183cb2..718979134 100755 --- a/packages/cli-hooks/src/get-hooks.js +++ b/packages/cli-hooks/src/get-hooks.js @@ -1,13 +1,14 @@ #!/usr/bin/env node import { fileURLToPath } from 'url'; +import fs from 'fs'; /** * Implementation the get-hooks script hook required by the Slack CLI. * Printed as an object containing featured provided by the SDK. */ -if (process.argv[1] === fileURLToPath(import.meta.url)) { +if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { console.log(JSON.stringify(getHooks())); // eslint-disable-line no-console } diff --git a/packages/cli-hooks/src/get-manifest.js b/packages/cli-hooks/src/get-manifest.js index 37ab01ab4..f00411ef3 100755 --- a/packages/cli-hooks/src/get-manifest.js +++ b/packages/cli-hooks/src/get-manifest.js @@ -9,7 +9,7 @@ import path from 'path'; * Printed as a well-formatted structure of project manifest data to stdout. */ -if (process.argv[1] === fileURLToPath(import.meta.url)) { +if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { const cwd = process.cwd(); const manifest = getManifestData(cwd); console.log(JSON.stringify(manifest)); // eslint-disable-line no-console diff --git a/packages/cli-hooks/src/start.js b/packages/cli-hooks/src/start.js index 147628ea8..4af8cc6e1 100755 --- a/packages/cli-hooks/src/start.js +++ b/packages/cli-hooks/src/start.js @@ -10,7 +10,7 @@ import fs from 'fs'; * The child processes will continue until exited or interrupted by the caller. */ -if (process.argv[1] === fileURLToPath(import.meta.url)) { +if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { start(process.cwd()); } From 26ed497ebed70188fedafe6ba880c40ec35a2e43 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 22:14:10 -0800 Subject: [PATCH 31/45] chore: bump the package patch version --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 35cd7455d..16cf8a947 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.9", + "version": "0.0.10", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From 7773a9d518efdb91e28a64d22bdb565c11a3a9a4 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 22:23:42 -0800 Subject: [PATCH 32/45] fix: include protocols in the packaged bundle --- packages/cli-hooks/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 16cf8a947..919ca612a 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -15,6 +15,7 @@ "src/check-update.js", "src/get-hooks.js", "src/get-manifest.js", + "src/protocols.js", "src/start.js" ], "engines": { From d5fd65d59b34a4256d48eb083e0e092ddd6cf854 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 22:24:17 -0800 Subject: [PATCH 33/45] refactor: rename protocol test file to match the implementation --- packages/cli-hooks/src/{protocol.spec.js => protocols.spec.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/cli-hooks/src/{protocol.spec.js => protocols.spec.js} (100%) diff --git a/packages/cli-hooks/src/protocol.spec.js b/packages/cli-hooks/src/protocols.spec.js similarity index 100% rename from packages/cli-hooks/src/protocol.spec.js rename to packages/cli-hooks/src/protocols.spec.js From 9aab3c9f3740405321df0fd2052b3b239736c5b2 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Wed, 24 Jan 2024 22:24:47 -0800 Subject: [PATCH 34/45] chore: bump the package patch version --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 919ca612a..e3bf47da9 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.10", + "version": "0.0.11", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From a6e72d3495c89c555148b9c0af0e96bfee93a33a Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Thu, 25 Jan 2024 17:14:45 -0800 Subject: [PATCH 35/45] fix: log responses with the protocol response --- packages/cli-hooks/src/check-update.js | 5 ++++- packages/cli-hooks/src/get-manifest.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/cli-hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js index 0167457f6..03cf9a72e 100755 --- a/packages/cli-hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -6,6 +6,8 @@ import childProcess from 'child_process'; import fs from 'fs'; import util from 'util'; +import { getProtocolInterface } from './protocols.js'; + const SLACK_BOLT_SDK = '@slack/bolt'; const SLACK_CLI_HOOKS = '@slack/cli-hooks'; @@ -15,7 +17,8 @@ const SLACK_CLI_HOOKS = '@slack/cli-hooks'; */ if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { - checkForSDKUpdates(process.cwd()).then(JSON.stringify).then(console.log); // eslint-disable-line no-console + const protocol = getProtocolInterface(process.argv.slice(1)); + checkForSDKUpdates(process.cwd()).then(JSON.stringify).then(protocol.respond); } /** diff --git a/packages/cli-hooks/src/get-manifest.js b/packages/cli-hooks/src/get-manifest.js index f00411ef3..a6e689cb8 100755 --- a/packages/cli-hooks/src/get-manifest.js +++ b/packages/cli-hooks/src/get-manifest.js @@ -4,15 +4,18 @@ import { fileURLToPath } from 'url'; import fs from 'fs'; import path from 'path'; +import { getProtocolInterface } from './protocols.js'; + /** * Implemention of the get-manifest hook that provides manifest information. * Printed as a well-formatted structure of project manifest data to stdout. */ if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { + const protocol = getProtocolInterface(process.argv.slice(1)); const cwd = process.cwd(); const manifest = getManifestData(cwd); - console.log(JSON.stringify(manifest)); // eslint-disable-line no-console + protocol.respond(JSON.stringify(manifest)); } /** From cb1c85e82d53071f31736f0544eef32fb75a7241 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Thu, 25 Jan 2024 17:15:18 -0800 Subject: [PATCH 36/45] feat: remove extraneous logs from the start hook --- packages/cli-hooks/src/start.js | 3 --- packages/cli-hooks/src/start.spec.js | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/cli-hooks/src/start.js b/packages/cli-hooks/src/start.js index 4af8cc6e1..2fd99207e 100755 --- a/packages/cli-hooks/src/start.js +++ b/packages/cli-hooks/src/start.js @@ -19,15 +19,12 @@ if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { * @param {string} cwd - The current working directory of the project. */ export default function start(cwd) { - // TODO - Format so that its less miss-able in output - console.log('Preparing local run in developer mode (Socket Mode)'); // eslint-disable-line no-console validateEnvironment(); const customPath = process.env.SLACK_CLI_CUSTOM_FILE_PATH; const pkgJSONMain = getPackageJSONMain(cwd); const pkgJSONDefault = 'app.js'; const fullPath = path.resolve(cwd, customPath || pkgJSONMain || pkgJSONDefault); - console.log(fullPath); // eslint-disable-line no-console const app = childProcess.spawn('node', [`${fullPath}`]); app.stdout.setEncoding('utf-8'); diff --git a/packages/cli-hooks/src/start.spec.js b/packages/cli-hooks/src/start.spec.js index 7d9df284e..a3aa7978c 100644 --- a/packages/cli-hooks/src/start.spec.js +++ b/packages/cli-hooks/src/start.spec.js @@ -80,7 +80,6 @@ describe('start implementation', async () => { mockSpawnProcess.stderr.on.callArgWith(1, 'warning'); mockSpawnProcess.on.callArgWith(1, 0); - assert.ok(consoleLogStub.calledWith('Preparing local run in developer mode (Socket Mode)')); assert.ok(spawnStub.called); assert.ok(spawnStub.calledWith('node', [path.resolve('tmp', 'start.js')])); assert.ok(stdoutWriteStub.calledWith('message')); @@ -96,7 +95,6 @@ describe('start implementation', async () => { mockSpawnProcess.stderr.on.callArgWith(1, 'watch out'); mockSpawnProcess.on.callArgWith(1, 2); - assert.ok(consoleLogStub.calledWith('Preparing local run in developer mode (Socket Mode)')); assert.ok(spawnStub.called); assert.ok(spawnStub.calledWith('node', [path.resolve('tmp', 'app.js')])); assert.ok(stdoutWriteStub.calledWith('defaults')); @@ -120,7 +118,6 @@ describe('start implementation', async () => { mockSpawnProcess.stderr.on.callArgWith(1, 'erroneous'); mockSpawnProcess.on.callArgWith(1, 4); - assert.ok(consoleLogStub.calledWith('Preparing local run in developer mode (Socket Mode)')); assert.ok(spawnStub.called); assert.ok(spawnStub.calledWith('node', [path.resolve('application.js')])); assert.ok(stdoutWriteStub.calledWith('startled')); From 614a965e97f4ccd3c6343e104d86bf6d03d6e4ba Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Thu, 25 Jan 2024 17:16:31 -0800 Subject: [PATCH 37/45] chore: bump the package patch version --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index e3bf47da9..4c8de165e 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.11", + "version": "0.0.12", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From f923d945fa4b951f8cc58beacd7ae0abf48931b1 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 10:09:02 -0800 Subject: [PATCH 38/45] test: display coverage after testing results --- packages/cli-hooks/.c8rc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/.c8rc.json b/packages/cli-hooks/.c8rc.json index c13ce1948..0c61fde48 100644 --- a/packages/cli-hooks/.c8rc.json +++ b/packages/cli-hooks/.c8rc.json @@ -1,7 +1,7 @@ { "include": ["src/*.js"], "exclude": ["**/*.spec.js"], - "reporter": ["lcov"], + "reporter": ["lcov", "text"], "all": false, "cache": true } From 91e139a5de96aecaa8c3fbe3f4191b993fe638d4 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 10:21:09 -0800 Subject: [PATCH 39/45] fix: use the exported `SUPPORTED_NAMED_PROTOCOLS` in get-hooks --- packages/cli-hooks/src/get-hooks.js | 4 +++- packages/cli-hooks/src/get-hooks.spec.js | 2 +- packages/cli-hooks/src/protocols.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/cli-hooks/src/get-hooks.js b/packages/cli-hooks/src/get-hooks.js index 718979134..1a3556da9 100755 --- a/packages/cli-hooks/src/get-hooks.js +++ b/packages/cli-hooks/src/get-hooks.js @@ -3,6 +3,8 @@ import { fileURLToPath } from 'url'; import fs from 'fs'; +import { SUPPORTED_NAMED_PROTOCOLS } from './protocols.js'; + /** * Implementation the get-hooks script hook required by the Slack CLI. * Printed as an object containing featured provided by the SDK. @@ -54,7 +56,7 @@ export default function getHooks() { '.', ], }, - 'protocol-version': ['message-boundaries', 'default'], + 'protocol-version': SUPPORTED_NAMED_PROTOCOLS, 'sdk-managed-connection-enabled': true, }, runtime: 'node', diff --git a/packages/cli-hooks/src/get-hooks.spec.js b/packages/cli-hooks/src/get-hooks.spec.js index f7be43004..acbedc9d8 100644 --- a/packages/cli-hooks/src/get-hooks.spec.js +++ b/packages/cli-hooks/src/get-hooks.spec.js @@ -13,7 +13,7 @@ describe('get-hooks implementation', async () => { it('should return every protocol version', async () => { const { config } = getHooks(); - assert.deepEqual(config['protocol-version'], ['message-boundaries', 'default']); + assert.deepEqual(config['protocol-version'], ['message-boundaries']); }); it('should return a true managed connection', async () => { diff --git a/packages/cli-hooks/src/protocols.js b/packages/cli-hooks/src/protocols.js index c87eda2ec..6ac0cabe6 100644 --- a/packages/cli-hooks/src/protocols.js +++ b/packages/cli-hooks/src/protocols.js @@ -27,7 +27,7 @@ import minimist from 'minimist'; const DEFAULT_PROTOCOL = 'default'; const MSG_BOUNDARY_PROTOCOL = 'message-boundaries'; -const SUPPORTED_NAMED_PROTOCOLS = [MSG_BOUNDARY_PROTOCOL]; +export const SUPPORTED_NAMED_PROTOCOLS = [MSG_BOUNDARY_PROTOCOL]; /** * The baseline CLI-SDK protocol. All responses in this protocol go to stdout. From 9a2b93125d03541f821ad4233a7d387e10692a88 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 10:26:03 -0800 Subject: [PATCH 40/45] test: assert missing boundary error text matches --- packages/cli-hooks/src/protocols.js | 2 +- packages/cli-hooks/src/protocols.spec.js | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/cli-hooks/src/protocols.js b/packages/cli-hooks/src/protocols.js index 6ac0cabe6..94756b042 100644 --- a/packages/cli-hooks/src/protocols.js +++ b/packages/cli-hooks/src/protocols.js @@ -61,7 +61,7 @@ export function BaseProtocol(args) { */ export function MessageBoundaryProtocol(args) { const { boundary } = parseArgs(args); - if (!boundary) throw new Error('no boundary argument provided!'); + if (!boundary) throw new Error('No boundary argument provided!'); const protocol = { name: MSG_BOUNDARY_PROTOCOL, log: console.log, // eslint-disable-line no-console diff --git a/packages/cli-hooks/src/protocols.spec.js b/packages/cli-hooks/src/protocols.spec.js index 8bbbfd305..c3dee0cf8 100644 --- a/packages/cli-hooks/src/protocols.spec.js +++ b/packages/cli-hooks/src/protocols.spec.js @@ -42,9 +42,12 @@ describe('protocol implementations', () => { }); it('errors if no boundary is specified', () => { - assert.throws(() => { - MessageBoundaryProtocol([]); - }); + assert.throws( + () => { + MessageBoundaryProtocol([]); + }, + /^Error: No boundary argument provided!$/, + ); }); it('uses the corresponding console methods', () => { From c7ded6e1dfc3700cee12329b98e708be439bd883 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 10:51:01 -0800 Subject: [PATCH 41/45] docs: improve remediation errors for missing start tokens --- packages/cli-hooks/src/start.js | 9 +++++++-- packages/cli-hooks/src/start.spec.js | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/cli-hooks/src/start.js b/packages/cli-hooks/src/start.js index 2fd99207e..741c48528 100755 --- a/packages/cli-hooks/src/start.js +++ b/packages/cli-hooks/src/start.js @@ -58,10 +58,15 @@ function getPackageJSONMain(cwd) { * Confirms environment variables are prepared by the CLI. */ function validateEnvironment() { + const missingTokenError = `Missing the {type} token needed to start the app with Socket Mode. +Hints: Setting the {token} environment variable is required. +Check: Confirm that you are using the latest version of the Slack CLI.`; if (!process.env.SLACK_CLI_XOXB) { - throw new Error('Missing local run bot token. Please see Slack CLI maintainers to troubleshoot.'); + const missingBotTokenError = missingTokenError.replace('{type}', 'bot').replace('{token}', 'SLACK_CLI_XOXB'); + throw new Error(missingBotTokenError); } if (!process.env.SLACK_CLI_XAPP) { - throw new Error('Missing local run app token. Please see Slack CLI maintainers to troubleshoot'); + const missingAppTokenError = missingTokenError.replace('{type}', 'app').replace('{token}', 'SLACK_CLI_XAPP'); + throw new Error(missingAppTokenError); } } diff --git a/packages/cli-hooks/src/start.spec.js b/packages/cli-hooks/src/start.spec.js index a3aa7978c..1561c72e9 100644 --- a/packages/cli-hooks/src/start.spec.js +++ b/packages/cli-hooks/src/start.spec.js @@ -145,7 +145,9 @@ describe('start implementation', async () => { start('./'); } catch (err) { if (err instanceof Error) { - assert(err.message.includes('Missing local run bot token')); + assert(err.message.includes('Missing the bot token needed to start the app with Socket Mode.')); + assert(err.message.includes('Hints: Setting the SLACK_CLI_XOXB environment variable is required.')); + assert(err.message.includes('Check: Confirm that you are using the latest version of the Slack CLI.')); return; } } @@ -158,7 +160,9 @@ describe('start implementation', async () => { start('./'); } catch (err) { if (err instanceof Error) { - assert(err.message.includes('Missing local run app token')); + assert(err.message.includes('Missing the app token needed to start the app with Socket Mode.')); + assert(err.message.includes('Hints: Setting the SLACK_CLI_XAPP environment variable is required.')); + assert(err.message.includes('Check: Confirm that you are using the latest version of the Slack CLI.')); return; } } From 6fe204b79a17cafe0a61bc07f7a5de0ee656dc13 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 10:58:58 -0800 Subject: [PATCH 42/45] refactor: call the base protocol the default protocol --- packages/cli-hooks/src/protocols.js | 8 ++++---- packages/cli-hooks/src/protocols.spec.js | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/cli-hooks/src/protocols.js b/packages/cli-hooks/src/protocols.js index 94756b042..929312a19 100644 --- a/packages/cli-hooks/src/protocols.js +++ b/packages/cli-hooks/src/protocols.js @@ -30,13 +30,13 @@ const MSG_BOUNDARY_PROTOCOL = 'message-boundaries'; export const SUPPORTED_NAMED_PROTOCOLS = [MSG_BOUNDARY_PROTOCOL]; /** - * The baseline CLI-SDK protocol. All responses in this protocol go to stdout. + * The default CLI-SDK protocol. All responses in this protocol go to stdout. * The CLI combines both stdout and stderr to interpret the hook response. * This simplistic protocol has inherent limitation: no logging diagnostics! * @param {string[]} args - Command-line arguments passed to this process. * @returns {Protocol} Specified communication rules for the SDK to follow. */ -export function BaseProtocol(args) { +export function DefaultProtocol(args) { const { manifest: manifestOnly = false } = parseArgs(args); // If the particular hook invocation is requesting manifest generation we @@ -105,8 +105,8 @@ export function getProtocolInterface(args) { } } - // If protocol negotiation fails for any reason, return the base protocol - return BaseProtocol(args); + // If protocol negotiation fails for any reason, return the default protocol + return DefaultProtocol(args); } /** diff --git a/packages/cli-hooks/src/protocols.spec.js b/packages/cli-hooks/src/protocols.spec.js index c3dee0cf8..fe2c17fdf 100644 --- a/packages/cli-hooks/src/protocols.spec.js +++ b/packages/cli-hooks/src/protocols.spec.js @@ -5,7 +5,7 @@ import assert from 'assert'; import sinon from 'sinon'; import { - BaseProtocol, + DefaultProtocol, MessageBoundaryProtocol, getProtocolInterface, } from './protocols.js'; @@ -13,7 +13,7 @@ import { describe('protocol implementations', () => { describe('default protocol', () => { it('stubs logging methods with a manifest flag', () => { - const protocol = BaseProtocol(['--manifest']); + const protocol = DefaultProtocol(['--manifest']); assert.notEqual(protocol.log, console.log); assert.notEqual(protocol.error, console.error); assert.notEqual(protocol.warn, console.warn); @@ -21,7 +21,7 @@ describe('protocol implementations', () => { }); it('uses console log methods without a manifest', () => { - const protocol = BaseProtocol(['--flag']); + const protocol = DefaultProtocol(['--flag']); assert.equal(protocol.log, console.log); assert.equal(protocol.error, console.log); assert.equal(protocol.warn, console.log); @@ -65,12 +65,12 @@ describe('protocol implementations', () => { }); describe('get protocol interface', () => { - it('returns the base protocol by default', () => { + it('returns the default protocol by default', () => { const protocol = getProtocolInterface([]).name; assert.equal(protocol, 'default'); }); - it('returns the base protocol if unrecognized', () => { + it('returns the default protocol if unrecognized', () => { const protocol = getProtocolInterface(['--protocol=cryptics']).name; assert.equal(protocol, 'default'); }); From c3b804ee77f888188b540b4be03f2e0274b05571 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 11:03:39 -0800 Subject: [PATCH 43/45] refactor: get the protocol implementation and not an interface --- packages/cli-hooks/src/check-update.js | 4 ++-- packages/cli-hooks/src/get-manifest.js | 4 ++-- packages/cli-hooks/src/protocols.js | 13 +++++++------ packages/cli-hooks/src/protocols.spec.js | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/cli-hooks/src/check-update.js b/packages/cli-hooks/src/check-update.js index 03cf9a72e..ec3b3dc9c 100755 --- a/packages/cli-hooks/src/check-update.js +++ b/packages/cli-hooks/src/check-update.js @@ -6,7 +6,7 @@ import childProcess from 'child_process'; import fs from 'fs'; import util from 'util'; -import { getProtocolInterface } from './protocols.js'; +import { getProtocol } from './protocols.js'; const SLACK_BOLT_SDK = '@slack/bolt'; const SLACK_CLI_HOOKS = '@slack/cli-hooks'; @@ -17,7 +17,7 @@ const SLACK_CLI_HOOKS = '@slack/cli-hooks'; */ if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { - const protocol = getProtocolInterface(process.argv.slice(1)); + const protocol = getProtocol(process.argv.slice(1)); checkForSDKUpdates(process.cwd()).then(JSON.stringify).then(protocol.respond); } diff --git a/packages/cli-hooks/src/get-manifest.js b/packages/cli-hooks/src/get-manifest.js index a6e689cb8..a86e66412 100755 --- a/packages/cli-hooks/src/get-manifest.js +++ b/packages/cli-hooks/src/get-manifest.js @@ -4,7 +4,7 @@ import { fileURLToPath } from 'url'; import fs from 'fs'; import path from 'path'; -import { getProtocolInterface } from './protocols.js'; +import { getProtocol } from './protocols.js'; /** * Implemention of the get-manifest hook that provides manifest information. @@ -12,7 +12,7 @@ import { getProtocolInterface } from './protocols.js'; */ if (fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) { - const protocol = getProtocolInterface(process.argv.slice(1)); + const protocol = getProtocol(process.argv.slice(1)); const cwd = process.cwd(); const manifest = getManifestData(cwd); protocol.respond(JSON.stringify(manifest)); diff --git a/packages/cli-hooks/src/protocols.js b/packages/cli-hooks/src/protocols.js index 929312a19..9c12a67db 100644 --- a/packages/cli-hooks/src/protocols.js +++ b/packages/cli-hooks/src/protocols.js @@ -84,24 +84,25 @@ const PROTOCOL_MAP = { }; /** - * Determines the protocol interface to use when communicating with the CLI. + * Determines the protocol implementation to use for communicating with the CLI. * Based on the arguments provided by the CLI to the SDK hook process. * @param {string[]} args - Command-line flags and arguments passed to the hook. * @returns {Protocol} The interface to follow when messaging to the CLI. */ -export function getProtocolInterface(args) { +export function getProtocol(args) { const { protocol: protocolRequestedByCLI } = parseArgs(args); if (protocolRequestedByCLI) { if (SUPPORTED_NAMED_PROTOCOLS.includes(protocolRequestedByCLI)) { - const iface = PROTOCOL_MAP[protocolRequestedByCLI]; + const protocol = PROTOCOL_MAP[protocolRequestedByCLI]; + // Allow support for protocol implementations to either be: // - a function, using arguments passed to this process to // dynamically instantiate a Protocol interface // - an object implementing the Protocol interface directly - if (typeof iface === 'function') { - return iface(args); + if (typeof protocol === 'function') { + return protocol(args); } - return iface; + return protocol; } } diff --git a/packages/cli-hooks/src/protocols.spec.js b/packages/cli-hooks/src/protocols.spec.js index fe2c17fdf..e99c3ea38 100644 --- a/packages/cli-hooks/src/protocols.spec.js +++ b/packages/cli-hooks/src/protocols.spec.js @@ -7,7 +7,7 @@ import sinon from 'sinon'; import { DefaultProtocol, MessageBoundaryProtocol, - getProtocolInterface, + getProtocol, } from './protocols.js'; describe('protocol implementations', () => { @@ -66,18 +66,18 @@ describe('protocol implementations', () => { describe('get protocol interface', () => { it('returns the default protocol by default', () => { - const protocol = getProtocolInterface([]).name; + const protocol = getProtocol([]).name; assert.equal(protocol, 'default'); }); it('returns the default protocol if unrecognized', () => { - const protocol = getProtocolInterface(['--protocol=cryptics']).name; + const protocol = getProtocol(['--protocol=cryptics']).name; assert.equal(protocol, 'default'); }); it('returns the specified message boundary protocol', () => { const args = ['--protocol=message-boundaries', '--boundary=racecar']; - const protocol = getProtocolInterface(args).name; + const protocol = getProtocol(args).name; assert.equal(protocol, 'message-boundaries'); }); }); From 980eee078e5420f9db2107cddec0e88bf5fa186e Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 11:45:56 -0800 Subject: [PATCH 44/45] chore: bump the package patch version --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 4c8de165e..092d1108d 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.12", + "version": "0.0.13", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT", From ab411ac78eab6b281ac3742705f676d852bdde44 Mon Sep 17 00:00:00 2001 From: Ethan Zimbelman Date: Fri, 26 Jan 2024 13:51:48 -0800 Subject: [PATCH 45/45] chore: release a major version of this package --- packages/cli-hooks/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli-hooks/package.json b/packages/cli-hooks/package.json index 092d1108d..693deddee 100644 --- a/packages/cli-hooks/package.json +++ b/packages/cli-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@slack/cli-hooks", - "version": "0.0.13", + "version": "1.0.0", "description": "Node implementation of the contract between the Slack CLI and Bolt for JavaScript", "author": "Slack Technologies, LLC", "license": "MIT",