diff --git a/.eslintrc.js b/.eslintrc.js index b587d60..8807744 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,16 +1,26 @@ module.exports = { + "extends": [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended' + ], + "parser": '@typescript-eslint/parser', + "plugins": [ + '@typescript-eslint' + ], "env": { "node": true, "es2020": true }, - "parserOptions": { "sourceType": "module" }, - - "extends": "eslint:recommended", - "rules": { "linebreak-style": ["error", "unix"] - } + }, + + "ignorePatterns": [ + "node_modules/", + "lib/", + "test/", + ] } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 40b878d..77e8817 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -node_modules/ \ No newline at end of file +node_modules/ +lib/ +coverage/ +/debug-playground.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c7c1623 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "./node_modules/typescript/lib" +} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..e66b945 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,17 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + transform: { + '\\.ts$': [ + 'ts-jest', + { + tsconfig: "./tsconfig.json" + } + ] + }, + collectCoverageFrom: [ + "src/**/*{!(.spec),}.ts" + ], + coverageReporters: ['lcov'] +}; \ No newline at end of file diff --git a/jest/helpers.ts b/jest/helpers.ts new file mode 100644 index 0000000..eea99f3 --- /dev/null +++ b/jest/helpers.ts @@ -0,0 +1,134 @@ +/* eslint @typescript-eslint/no-empty-interface: off, @typescript-eslint/no-namespace: off */ +export {} + +interface CustomMatchers { + toBeAnOperator(): R; + toHaveOwnProperty(key: string, value?: unknown): R; + toAsyncThrow(): R; +} + +declare global { + namespace jest { + interface Expect extends CustomMatchers {} + interface Matchers extends CustomMatchers {} + interface InverseAsymmetricMatchers extends CustomMatchers {} + } +} + +interface IResult { + pass: boolean; + message: () => string; +} + +const hasOwnProperty = Object.prototype.hasOwnProperty + +expect.extend({ + + //eslint-disable-next-line @typescript-eslint/no-explicit-any + toBeAnOperator: (subject: any) => { + if (subject == null) { + return { pass: false, message: () => `expected subject to be an operator definition` }; + } + if (typeof subject.name !== 'string') { + return { pass: false, message: () => `name must be a string` } + } + if (typeof subject.description !== 'string') { + return { pass: false, message: () => `description must be a string` } + } + if (!Number.isFinite(subject.quantifier)) { + return { pass: false, message: () => `arguments quantifier must be a numeric value` } + } + if (subject.defer != null && typeof subject.defer !== 'boolean') { + return { pass: false, message: () => `defer must be a boolean value` } + } + if (subject.cased != null && typeof subject.cased !== 'boolean') { + return { pass: false, message: () => `cased must be a boolean value` } + } + if ( + !Array.isArray(subject.alias) || + subject.alias.some((value: unknown) => typeof value !== 'string') + ) { + return { pass: false, message: () => `alias must be a array of strings` } + } + if (subject.inverse != null) { + if (typeof subject.inverse !== 'object') { + return { pass: false, message: () => `inverse must be an object` } + } + + const inverse : Record = subject.inverse; + if (typeof inverse.description !== 'string') { + return { pass: false, message: () => `inverse description must be a string` } + } + if ( + !Array.isArray(inverse.alias) || + inverse.alias.some((value: unknown) => typeof value !== 'string') + ) { + return { pass: false, message: () => `inverse alias must be an array of strings` } + } + if ( + inverse.handle != null && + ( + typeof inverse.handle !== 'function' || + !(inverse.handle instanceof Function) + ) + ) { + return { pass: false, message: () => `inverse handle must be a function`} + } + } + if ( + typeof subject.handle !== 'function' || + !(subject.handle instanceof Function) + ) { + return { pass: false, message: () => `handle must be a function`} + } + + + return { pass: true, message: () => `expected subject not to be an operator definition` } + }, + + //eslint-disable-next-line @typescript-eslint/no-explicit-any + toHaveOwnProperty: (...args: any[]) : IResult => { + + const [subject, key, value] = args; + + if (!hasOwnProperty.call(subject, key)) { + return { + pass: false, + message: () => `expected subject to have '${key}'` + }; + + } else if (args.length < 3) { + return { + pass: true, + message: () => `expected subject not to have '${key}' as a property` + }; + + } else if (subject[key] === value) { + return { + pass: true, + message: () => `expected subject '${key}' not to equal ${value}` + }; + } else { + return { + pass: false, + message: () => `expected subject '${key}' to equal ${value}` + }; + } + }, + + toAsyncThrow: async (subject: () => unknown) : Promise => { + expect.assertions(1); + try { + await subject(); + return { + pass: false, + message: () => `expected subject to throw an error` + }; + } catch (err) { + return { + pass: true, + message: () => `subject did not throw an error` + } + } + } +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0bc7488..c4645b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,49 +1,5699 @@ { "name": "expressionish", - "version": "0.0.1", - "lockfileVersion": 1, + "version": "2.0.0", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "expressionish", + "version": "2.0.0", + "license": "ISC", + "devDependencies": { + "@types/jest": "^29.0.3", + "@types/node": "^18.7.18", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", + "eslint": "^8.4.1", + "jest": "^29.0.3", + "ts-jest": "^29.0.1", + "typescript": "^4.8.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", + "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", + "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.1", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", + "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.19.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", + "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.1", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", + "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", + "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", + "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.1", + "@babel/types": "^7.19.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.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/@eslint/eslintrc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", + "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.2.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", + "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/@jest/console": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz", + "integrity": "sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz", + "integrity": "sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.0.3", + "@jest/reporters": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-resolve-dependencies": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "jest-watcher": "^29.0.3", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.3.tgz", + "integrity": "sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ==", + "dev": true, + "dependencies": { + "expect": "^29.0.3", + "jest-snapshot": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz", + "integrity": "sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.3.tgz", + "integrity": "sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz", + "integrity": "sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/types": "^29.0.3", + "jest-mock": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz", + "integrity": "sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz", + "integrity": "sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz", + "integrity": "sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz", + "integrity": "sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.3.tgz", + "integrity": "sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "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/@sinclair/typebox": { + "version": "0.24.42", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.42.tgz", + "integrity": "sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", + "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", + "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.12", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz", + "integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz", + "integrity": "sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/type-utils": "5.37.0", + "@typescript-eslint/utils": "5.37.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.37.0.tgz", + "integrity": "sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", + "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", + "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.37.0", + "@typescript-eslint/utils": "5.37.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", + "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", + "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", + "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", + "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.37.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "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.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "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-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/babel-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", + "integrity": "sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.0.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001409", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz", + "integrity": "sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "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/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "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/debug/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/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": 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 + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.256", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", + "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.0.5", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.2.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "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-scope": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", + "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/espree": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.2.0.tgz", + "integrity": "sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==", + "dev": true, + "dependencies": { + "acorn": "^8.6.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.1.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "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, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "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-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "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.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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/globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/globby/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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/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/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "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": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "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-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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-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-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.0.3", + "@jest/types": "^29.0.3", + "import-local": "^3.0.2", + "jest-cli": "^29.0.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz", + "integrity": "sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "p-limit": "^3.1.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz", + "integrity": "sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz", + "integrity": "sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.0.3", + "@jest/types": "^29.0.3", + "babel-jest": "^29.0.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.0.3", + "jest-environment-node": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz", + "integrity": "sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz", + "integrity": "sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "jest-util": "^29.0.3", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz", + "integrity": "sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz", + "integrity": "sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz", + "integrity": "sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz", + "integrity": "sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz", + "integrity": "sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.0.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.3.tgz", + "integrity": "sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/node": "*" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz", + "integrity": "sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz", + "integrity": "sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz", + "integrity": "sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw==", + "dev": true, + "dependencies": { + "@jest/console": "^29.0.3", + "@jest/environment": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-leak-detector": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-resolve": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-util": "^29.0.3", + "jest-watcher": "^29.0.3", + "jest-worker": "^29.0.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz", + "integrity": "sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/globals": "^29.0.3", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz", + "integrity": "sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "natural-compare": "^1.4.0", + "pretty-format": "^29.0.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.3.tgz", + "integrity": "sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz", + "integrity": "sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "leven": "^3.1.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/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/jest-watcher": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz", + "integrity": "sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^29.0.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz", + "integrity": "sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/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/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/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": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "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/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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/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/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz", + "integrity": "sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "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.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.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-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/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-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "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/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/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": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.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/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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-jest": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.1.tgz", + "integrity": "sha512-htQOHshgvhn93QLxrmxpiQPk69+M1g7govO1g6kf6GsjCv4uvRV0znVmDrrvjUrVCnTYeY4FBxTYYYD4airyJA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "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/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "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.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "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/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" + } + } + }, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", + "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", + "dev": true + }, + "@babel/core": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", + "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.1", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", + "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "dev": true, + "requires": { + "@babel/types": "^7.19.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", + "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.19.1", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", + "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", + "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", + "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.1", + "@babel/types": "^7.19.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@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 + }, "@eslint/eslintrc": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", "dev": true, "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.2.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.2.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", + "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@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 + }, + "@jest/console": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz", + "integrity": "sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz", + "integrity": "sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ==", + "dev": true, + "requires": { + "@jest/console": "^29.0.3", + "@jest/reporters": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-resolve-dependencies": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "jest-watcher": "^29.0.3", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.3.tgz", + "integrity": "sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3" + } + }, + "@jest/expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ==", + "dev": true, + "requires": { + "expect": "^29.0.3", + "jest-snapshot": "^29.0.3" + } + }, + "@jest/expect-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz", + "integrity": "sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q==", + "dev": true, + "requires": { + "jest-get-type": "^29.0.0" } }, - "@humanwhocodes/config-array": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", - "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "@jest/fake-timers": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.3.tgz", + "integrity": "sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@jest/types": "^29.0.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" } }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "@jest/globals": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz", + "integrity": "sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/types": "^29.0.3", + "jest-mock": "^29.0.3" + } + }, + "@jest/reporters": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz", + "integrity": "sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + } + }, + "@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/source-map": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz", + "integrity": "sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg==", + "dev": true, + "requires": { + "@jest/console": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz", + "integrity": "sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ==", + "dev": true, + "requires": { + "@jest/test-result": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz", + "integrity": "sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "@jest/types": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.3.tgz", + "integrity": "sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true }, - "@ungap/promise-all-settled": { + "@jridgewell/set-array": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@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, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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 + }, + "@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, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@sinclair/typebox": { + "version": "0.24.42", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.42.tgz", + "integrity": "sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", + "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/node": { + "version": "18.7.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", + "dev": true + }, + "@types/prettier": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", + "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.12", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.12.tgz", + "integrity": "sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz", + "integrity": "sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/type-utils": "5.37.0", + "@typescript-eslint/utils": "5.37.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.37.0.tgz", + "integrity": "sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", + "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", + "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.37.0", + "@typescript-eslint/utils": "5.37.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", + "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", "dev": true }, + "@typescript-eslint/typescript-estree": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", + "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", + "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", + "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.37.0", + "eslint-visitor-keys": "^3.3.0" + } + }, "acorn": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", @@ -54,7 +5704,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "ajv": { "version": "6.12.6", @@ -74,6 +5725,23 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -105,18 +5773,88 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "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 + }, + "babel-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", + "integrity": "sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==", + "dev": true, + "requires": { + "@jest/transform": "^29.0.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^29.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, "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 }, - "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 - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -136,10 +5874,40 @@ "fill-range": "^7.0.1" } }, - "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==", + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, "callsites": { @@ -149,9 +5917,15 @@ "dev": true }, "camelcase": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", - "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001409", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz", + "integrity": "sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==", "dev": true }, "chalk": { @@ -162,34 +5936,25 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "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, - "requires": { - "has-flag": "^4.0.0" - } - } } }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - } + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "ci-info": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true }, "cliui": { "version": "7.0.4", @@ -202,6 +5967,18 @@ "wrap-ansi": "^7.0.0" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -223,6 +6000,15 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -235,9 +6021,9 @@ } }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -251,10 +6037,10 @@ } } }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "deep-is": { @@ -263,12 +6049,33 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff-sequences": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", "dev": true }, + "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, + "requires": { + "path-type": "^4.0.0" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -278,6 +6085,18 @@ "esutils": "^2.0.2" } }, + "electron-to-chromium": { + "version": "1.4.256", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", + "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==", + "dev": true + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -293,6 +6112,15 @@ "ansi-colors": "^4.1.1" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -390,9 +6218,9 @@ } }, "eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "espree": { @@ -406,6 +6234,12 @@ "eslint-visitor-keys": "^3.1.0" } }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, "esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -436,12 +6270,61 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3" + } + }, "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 }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@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" + } + }, "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", @@ -454,6 +6337,24 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -473,21 +6374,15 @@ } }, "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^6.0.0", + "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -517,22 +6412,46 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, "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 }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -561,22 +6480,59 @@ "type-fest": "^0.20.2" } }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "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 }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "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 + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "ignore": { @@ -595,6 +6551,16 @@ "resolve-from": "^4.0.0" } }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -617,13 +6583,19 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "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==", + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "dev": true, "requires": { - "binary-extensions": "^2.0.0" + "has": "^1.0.3" } }, "is-extglob": { @@ -638,6 +6610,12 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -653,22 +6631,508 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "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==", + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "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==", + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ==", + "dev": true, + "requires": { + "@jest/core": "^29.0.3", + "@jest/types": "^29.0.3", + "import-local": "^3.0.2", + "jest-cli": "^29.0.3" + } + }, + "jest-changed-files": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz", + "integrity": "sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "p-limit": "^3.1.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-cli": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz", + "integrity": "sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ==", + "dev": true, + "requires": { + "@jest/core": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz", + "integrity": "sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.0.3", + "@jest/types": "^29.0.3", + "babel-jest": "^29.0.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.0.3", + "jest-environment-node": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz", + "integrity": "sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + } + }, + "jest-docblock": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz", + "integrity": "sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "jest-util": "^29.0.3", + "pretty-format": "^29.0.3" + } + }, + "jest-environment-node": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz", + "integrity": "sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + } + }, + "jest-get-type": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", + "dev": true + }, + "jest-haste-map": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz", + "integrity": "sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz", + "integrity": "sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ==", + "dev": true, + "requires": { + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + } + }, + "jest-matcher-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz", + "integrity": "sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + } + }, + "jest-message-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz", + "integrity": "sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.0.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.3.tgz", + "integrity": "sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", "dev": true }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "jest-resolve": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz", + "integrity": "sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz", + "integrity": "sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw==", + "dev": true, + "requires": { + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.0.3" + } + }, + "jest-runner": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz", + "integrity": "sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw==", + "dev": true, + "requires": { + "@jest/console": "^29.0.3", + "@jest/environment": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-leak-detector": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-resolve": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-util": "^29.0.3", + "jest-watcher": "^29.0.3", + "jest-worker": "^29.0.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + } + }, + "jest-runtime": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz", + "integrity": "sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/globals": "^29.0.3", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-snapshot": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz", + "integrity": "sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "natural-compare": "^1.4.0", + "pretty-format": "^29.0.3", + "semver": "^7.3.5" + } + }, + "jest-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.3.tgz", + "integrity": "sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz", + "integrity": "sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "leven": "^3.1.0", + "pretty-format": "^29.0.3" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz", + "integrity": "sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw==", + "dev": true, + "requires": { + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^29.0.3", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz", + "integrity": "sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { @@ -680,6 +7144,18 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -692,6 +7168,24 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -702,31 +7196,33 @@ "type-check": "~0.4.0" } }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^5.0.0" + "p-locate": "^4.1.0" } }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, "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 }, - "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, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -736,6 +7232,66 @@ "yallist": "^4.0.0" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -745,62 +7301,39 @@ "brace-expansion": "^1.1.7" } }, - "mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - } - }, - "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 - }, - "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, "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 }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -810,6 +7343,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -834,14 +7376,31 @@ } }, "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "p-limit": "^3.0.2" + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } } }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -851,6 +7410,18 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -869,47 +7440,103 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "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 + }, + "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 + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "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 }, + "pretty-format": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz", + "integrity": "sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } + "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 }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, "regexpp": { "version": "3.2.0", @@ -920,15 +7547,55 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "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 }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -938,30 +7605,30 @@ "glob": "^7.1.3" } }, + "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, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "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==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "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, - "requires": { - "randombytes": "^2.1.0" - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -977,6 +7644,73 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -997,6 +7731,18 @@ "ansi-regex": "^5.0.1" } }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -1004,20 +7750,69 @@ "dev": true }, "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "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, "requires": { "has-flag": "^4.0.0" } }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "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 + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "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, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1027,6 +7822,37 @@ "is-number": "^7.0.0" } }, + "ts-jest": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.1.tgz", + "integrity": "sha512-htQOHshgvhn93QLxrmxpiQPk69+M1g7govO1g6kf6GsjCv4uvRV0znVmDrrvjUrVCnTYeY4FBxTYYYD4airyJA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1036,12 +7862,34 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "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 }, + "typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1057,6 +7905,26 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -1072,12 +7940,6 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1095,6 +7957,16 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -1108,38 +7980,26 @@ "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "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 }, - "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, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index ad6533b..245f52d 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,27 @@ { "name": "expressionish", "author": "SReject", - "version": "0.0.1", - "private": true, + "version": "2.0.0", "license": "ISC", "type": "commonjs", - "main": "./src/evaluate.js", + "main": "./lib/index.js", "scripts": { - "lint": "eslint --fix ./src/** ./test/**", - "test": "mocha" + "lint": "eslint .", + "test": "jest", + "build": "tsc --build", + "prepack": "eslint && mocha && tsc && echo Expressionish packed successfully" }, "devDependencies": { + "@types/jest": "^29.0.3", + "@types/node": "^18.7.18", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", "eslint": "^8.4.1", - "mocha": "^9.1.3" - } + "jest": "^29.0.3", + "ts-jest": "^29.0.1", + "typescript": "^4.8.3" + }, + "files": [ + "lib/" + ] } diff --git a/src/errors.js b/src/errors.js deleted file mode 100644 index 2cbc355..0000000 --- a/src/errors.js +++ /dev/null @@ -1,41 +0,0 @@ -class ExpressionError extends Error { - constructor(message, position) { - super(message); - - Error.captureStackTrace(this, this.constructor); - this.message = message; - this.position = position || 0; - } -} -class ExpressionSyntaxError extends ExpressionError { - constructor(message, position, character) { - super(message, position); - - Error.captureStackTrace(this, this.constructor); - this.character = character; - } -} -class ExpressionVariableError extends ExpressionError { - constructor(message, position, varname) { - super(message, position); - - Error.captureStackTrace(this, this.constructor); - this.varname = varname; - } -} -class ExpressionArgumentsError extends ExpressionError { - constructor(message, position, index, varname) { - super(message, position); - - Error.captureStackTrace(this, this.constructor); - this.index = index || -1; - this.varname = varname; - } -} - -module.exports = { - ExpressionError, - ExpressionSyntaxError, - ExpressionVariableError, - ExpressionArgumentsError -} \ No newline at end of file diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 0000000..a7d13ab --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,66 @@ +export class ExpressionError extends Error { + public readonly position: number; + + constructor(message: string, position: void | number) { + super(message); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + + this.position = position || 0; + } +} + +export class ExpressionSyntaxError extends ExpressionError { + public readonly character: string; + + constructor(message: string, position: void | number, character?: string) { + super(message, position); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + + this.character = character || ''; + } +} + +export class ExpressionVariableError extends ExpressionError { + public readonly varname: string; + + constructor( + message: string, + position: undefined | number, + varname?: string + ) { + super(message, position); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + + this.varname = varname || ''; + } +} + +export class ExpressionArgumentsError extends ExpressionError { + public readonly index: number; + public readonly varname: undefined | string; + + constructor( + message: string, + position: undefined | number, + varname: undefined | string, + index?: number + ) { + super(message, position); + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + + this.index = index || -1; + this.varname = varname; + } +} \ No newline at end of file diff --git a/src/evaluate.js b/src/evaluate.js deleted file mode 100644 index 9d6e4bd..0000000 --- a/src/evaluate.js +++ /dev/null @@ -1,66 +0,0 @@ -const { - ExpressionError, - ExpressionSyntaxError, - ExpressionVariableError, - ExpressionArgumentsError -} = require('./errors.js'); - -const tokenize = require('./tokens/index.js'); - -/** -** @param {object} options -** @param {Map} options.handlers -** @param {string} options.expression -** @param {object} options.metadata -** @param {!any} options.trigger -*/ -async function evaluate(options) { - - if (options == null) { - throw new TypeError('options not specified'); - } - - // validate handlers list - if (options.handlers == null) { - throw new TypeError('handlers list null'); - } - if (!(options.handlers instanceof Map)) { - throw new TypeError('handlers list is not a Map'); - } - - // validate options.trigger - if (options.trigger == null) { - throw new TypeError('No trigger defined in options'); - } - - // Validate expression - if (options.expression == null) { - throw new TypeError('expression not specified'); - } - if (typeof options.expression !== 'string') { - throw new TypeError('expression must be a string'); - } - - // tokenize expression - const tokens = tokenize(options.expression); - - // evaluate - const result = []; - for (let idx = 0; idx < tokens.length; idx += 1) { - let token = await tokens[idx].evaluate(options); - if (token == null) { - result.push(''); - } else { - result.push(token); - } - } - - // return result - return result.join(''); -} - -module.exports = evaluate; -module.exports.ExpressionError = ExpressionError; -module.exports.ExpressionSyntaxError = ExpressionSyntaxError; -module.exports.ExpressionVariableError = ExpressionVariableError; -module.exports.ExpressionArgumentsError = ExpressionArgumentsError; \ No newline at end of file diff --git a/src/expressionish/default/block-operators.ts b/src/expressionish/default/block-operators.ts new file mode 100644 index 0000000..e41f54f --- /dev/null +++ b/src/expressionish/default/block-operators.ts @@ -0,0 +1,3 @@ +import { type IOperatorOptionsDefinition } from '../options/operators'; + +export default []; \ No newline at end of file diff --git a/src/expressionish/default/comparison-operators.ts b/src/expressionish/default/comparison-operators.ts new file mode 100644 index 0000000..e41f54f --- /dev/null +++ b/src/expressionish/default/comparison-operators.ts @@ -0,0 +1,3 @@ +import { type IOperatorOptionsDefinition } from '../options/operators'; + +export default []; \ No newline at end of file diff --git a/src/expressionish/default/function-handlers.ts b/src/expressionish/default/function-handlers.ts new file mode 100644 index 0000000..7499008 --- /dev/null +++ b/src/expressionish/default/function-handlers.ts @@ -0,0 +1,3 @@ +import { type IOperatorDefinition } from '../options'; + +export default >{}; \ No newline at end of file diff --git a/src/expressionish/default/special-sequences.ts b/src/expressionish/default/special-sequences.ts new file mode 100644 index 0000000..022389c --- /dev/null +++ b/src/expressionish/default/special-sequences.ts @@ -0,0 +1,5 @@ +export default >{ + 't': '\t', + 'n': '\n', + 'r': '\r' +}; \ No newline at end of file diff --git a/src/expressionish/index.ts b/src/expressionish/index.ts new file mode 100644 index 0000000..90f9cf1 --- /dev/null +++ b/src/expressionish/index.ts @@ -0,0 +1,422 @@ +import has from '../helpers/has'; +import freeze from '../helpers/deep-freeze'; + +import { IQuantifiedList, verifyQuantifiedList } from './options/_support'; + +import quantifyEndOfLine, { + type IEndOfLineOptions, + type IEndOfLineQuantified +} from './options/end-of-line'; + +import quantifySpecialSignifier from './options/special-signifier'; + +import quantifyFunctionSignifier from './options/function-signifier'; + +import quantifyGroupSignifier, { + type IGroupSignifierOptions, + type IGroupSignifierQuantified +} from './options/group-signifier'; + +import quantifyQuotesSignifiers, { + type IQuotesOptions, + type IQuotesQuantified +} from './options/quotes-signifiers' + +import quantifySpecialSequences, { + type ISpecialSequencesOptions, + type ISpecialSequencesQuantified +} from './options/special-sequences'; + +import expandOperator, { + OperatorQuantifier, + type IOperatorOptionsDefinition, + type IOperatorOptions, + type IOperatorQuantified +} from './options/operators'; + +import quantifyFunctionHandlers, { + type IFunctionHandlersOptions, + type IFunctionHandlersQuantified +} from './options/function-handlers'; + + + + +import { + type IHandleFnc, + // type IOperatorDefinition, + type ILookupHandler, +} from './options'; +import defaultComparisonOperators from './default/comparison-operators'; +import defaultBlockOperators from './default/block-operators'; +import defaultFunctionHandlers from './default/function-handlers'; +import { ExpressionError, ExpressionArgumentsError, ExpressionSyntaxError, ExpressionVariableError } from '../errors'; + + + + +interface IExpressionOptions { + eol?: IEndOfLineOptions; + specialSignifier?: string; + functionSignifier?: string; + groupSignifier?: IGroupSignifierOptions; + quotes?: IQuotesOptions; + specialSequences?: ISpecialSequencesOptions; + comparisonOperators?: IOperatorOptions; + blockOperators?: IOperatorOptions; + + functionHandlers?: IFunctionHandlersOptions; + +} +class Expressionish { + + private eol : IEndOfLineQuantified; + private specialSignifier: string; + private functionSignifier : string; + private groupSignifier: IGroupSignifierQuantified; + private quotes : IQuotesQuantified[]; + private specialSequences : ISpecialSequencesQuantified; + private comparisonOperators: Record; + private blockOperators: Record; + private functionHandlers : Record; + + private lookupHandlers : Record; + + constructor(options: IExpressionOptions = {}) { + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const define = (key: string, value: unknown, deepFreeze = false) => { + return Object.defineProperty(this, key, { + configurable: false, + enumerable: false, + writable: false, + value: freeze(value, deepFreeze) + }); + } + + + define( + 'eol', + quantifyEndOfLine(options.eol) + ); + + + define( + 'specialSignifier', + quantifySpecialSignifier(options.specialSignifier) + ); + const signifiers : string[] = [this.specialSignifier]; + + + define( + 'functionSignifier', + quantifyFunctionSignifier( + options.functionSignifier, + signifiers + ) + ); + signifiers.push(this.functionSignifier); + + + define('groupSignifier', + quantifyGroupSignifier( + options.groupSignifier, + signifiers + ), + true + ); + signifiers.push(this.groupSignifier.open, this.groupSignifier.delimiter, this.groupSignifier.close); + + + define('quotes', + quantifyQuotesSignifiers( + options.quotes, + [ + this.specialSignifier, + this.functionSignifier, + this.groupSignifier.open, + this.groupSignifier.delimiter, + this.groupSignifier.close + ] + ), + true + ); + this.quotes.forEach(quoteDef => { + if (!signifiers.includes(quoteDef.open)) + signifiers.push(quoteDef.open); + if (!signifiers.includes(quoteDef.close)) + signifiers.push(quoteDef.close); + }); + + + + define( + 'specialSequences', + quantifySpecialSequences(options.specialSequences), + true + ); + + + /* #region Comparison Operators */ + define('comparisonOperators', {}); + /* + define( + 'comparisonOperators', + quantifyOperators( + options.comparisonOperators, + signifiers, + defaultComparisonOperators, + {} + ) + ); + define( + 'blockOperators', + quantifyOperators( + options.blockOperators, + signifiers, + defaultBlockOperators, + this.comparisonOperators + ) + ) + */ + const comparisonOperators = options.comparisonOperators; + if (comparisonOperators == null || comparisonOperators === true) { + this.registerComparisonOperators(defaultComparisonOperators); + + } else if (typeof comparisonOperators === 'object') { + verifyQuantifiedList(comparisonOperators); + if (comparisonOperators.disposition === 'append') { + this.registerComparisonOperators(defaultComparisonOperators); + } + this.registerComparisonOperators(comparisonOperators.items); + } else if (comparisonOperators !== false) { + throw new Error('TODO'); + } + /* #endregion */ + + + /* #region Block Operators */ + define('blockOperators', {}); + const blockOperators = options.blockOperators; + if (blockOperators == null || blockOperators === true) { + this.registerBlockOperators(defaultBlockOperators); + } else if (typeof blockOperators === 'object') { + verifyQuantifiedList(blockOperators); + if (blockOperators.disposition === 'append') { + this.registerBlockOperators(defaultBlockOperators); + } + this.registerBlockOperators(blockOperators.items); + } else if (blockOperators !== false) { + throw new Error('TODO'); + } + /* #endregion */ + + + /* #region Function Handlers */ + define('functionHandlers', {}); + const functionHandlers = options.functionHandlers; + if (functionHandlers == null || functionHandlers === true) { + this.registerFunctionHandlers(defaultFunctionHandlers); + } else if (typeof functionHandlers === 'object') { + verifyQuantifiedList(functionHandlers); + if (functionHandlers.disposition === 'append') { + this.registerFunctionHandlers(defaultFunctionHandlers); + } + this.registerFunctionHandlers(functionHandlers.items); + } else if (functionHandlers !== false) { + throw new Error('TODO'); + } + + + /* #region lookup handlers */ + define('lookupHandlers', {}); + if (typeof options.lookupHandlers !== 'object') { + throw new Error('TODO'); + } else if (options.lookupHandlers != null) { + this.registerLookupHandlers(options.lookupHandlers); + } + /* #endregion */ + + + Object.freeze(this); + } + + + + registerComparisonOperator(operator: IOperatorOptionsDefinition) { + const signifiers : string[] = [ + this.specialSignifier, + this.functionSignifier, + this.groupSignifier.open, + this.groupSignifier.delimiter, + this.groupSignifier.close + ]; + this.quotes.forEach(quotedef => { + if (!signifiers.includes(quotedef.open)) { + signifiers.push(quotedef.open); + } + if (!signifiers.includes(quotedef.close)) { + signifiers.push(quotedef.close); + } + }); + + expandOperator(signifiers, this.comparisonOperators, operator); + } + registerComparisonOperators(operators: IOperatorOptionsDefinition[]) { + if (!Array.isArray(operators)) { + throw new Error('TODO'); + } + operators.forEach(operator => this.registerComparisonOperator(operator)); + } + + + + registerBlockOperator(operator: IOperatorOptionsDefinition) { + const signifiers : string[] = [ + this.specialSignifier, + this.functionSignifier, + this.groupSignifier.open, + this.groupSignifier.delimiter, + this.groupSignifier.close + ]; + this.quotes.forEach(quotedef => { + if (!signifiers.includes(quotedef.open)) { + signifiers.push(quotedef.open); + } + if (!signifiers.includes(quotedef.close)) { + signifiers.push(quotedef.close); + } + }); + expandOperator(signifiers, this.blockOperators, operator) + } + registerBlockOperators(operators: IOperatorOptionsDefinition[]) { + if (!Array.isArray(operators)) { + throw new Error('TODO'); + } + operators.forEach(operator => this.registerBlockOperator(operator)); + } + + + + registerFunctionHandler(name: string, handler: IFunctionHandler | IHandleFnc) { + if (typeof name !== 'string') { + throw new Error('TODO'); + } else if (!/^[a-z][a-z\d]{2,}$/i.test(name)) { + throw new Error('TODO'); + } else if (has(this.functionHandlers, name.toLowerCase())) { + throw new Error('TODO'); + } else if (typeof handler === 'function') { + this.functionHandlers[name.toLowerCase()] = { defer: false, evaluate: handler }; + } else if (handler == null || typeof handler !== 'object') { + throw new Error('TODO'); + } else if (handler.defer != null && typeof handler.defer !== 'boolean') { + throw new Error('TODO'); + } else if (handler.stackCheck != null && typeof handler.stackCheck !== 'function') { + throw new Error('TODO'); + } else if (handler.argsCheck != null && typeof handler.argsCheck !== 'function') { + throw new Error('TODO'); + } else if (handler.evaluate == null || typeof handler.evaluate !== 'function') { + throw new Error('TODO'); + } else { + const { defer, stackCheck, argsCheck, evaluate } = handler; + this.functionHandlers[name.toLowerCase()] = Object.freeze({ + defer: !!defer, + stackCheck, + argsCheck, + evaluate + }); + } + } + registerFunctionHandlers(list: Record>) { + if (list == null) { + throw new Error('TODO'); + } else if (typeof list !== 'object') { + throw new Error('TODO'); + } else { + Object.keys(list).forEach(prefix => { + this.registerFunctionHandler(prefix, list[prefix]); + }); + } + } + registerLookupHandler(prefix: string, handler: ILookupHandler) { + if (typeof prefix !== 'string') { + throw new Error('TODO'); + } else if ( + prefix === '' || + /[!\s\\[,\]"`]/.test(prefix) || + prefix.includes(this.functionSignifier) + ) { + throw new Error('TODO'); + } else if (has(this.lookupHandlers, prefix.toLowerCase())) { + throw new Error('TODO'); + } else if (typeof handler !== 'function') { + throw new Error('TODO'); + } else { + this.lookupHandlers[prefix.toLowerCase()] = handler; + } + } + registerLookupHandlers(list: Record) { + if (list == null) { + throw new Error('TODO'); + } else if (typeof list !== 'object') { + throw new Error('TODO'); + } else { + Object.keys(list).forEach(prefix => { + this.registerLookupHandler(prefix, list[prefix]); + }); + } + } + + tokenize(subject: string) { + // todo + } + + toJSON() : Record { + const comparisonOperators : Record = {}; + Object.keys(this.comparisonOperators).forEach(operatorName => { + const { signifier, quantifier, cased, defer } = this.comparisonOperators[operatorName]; + comparisonOperators[operatorName] = { signifier, quantifier, cased, defer }; + }); + + const blockOperators : Record = {}; + Object.keys(this.blockOperators).forEach(operatorName => { + const { signifier, quantifier, cased, defer } = this.blockOperators[operatorName]; + blockOperators[operatorName] = { signifier, quantifier, cased, defer }; + }); + + const functionHandlers : Record = {}; + Object.keys(this.functionHandlers).forEach(funcName => { + const { defer } = this.functionHandlers[funcName]; + functionHandlers[funcName] = { defer }; + }); + + return { + eol: this.eol.quantifier, + escapeSignifier: this.escapeSignifier, + functionSignifier: this.functionSignifier, + groupSignifier: this.groupSignifier, + quotes: this.quotes, + specialSequences: this.specialSequences, + comparisonOperators, + blockOperators, + functionHandlers, + lookupHandlers: Object.keys(this.lookupHandlers) + }; + } +} + +export { + ExpressionError, + ExpressionSyntaxError, + ExpressionVariableError, + ExpressionArgumentsError, + + OperatorQuantifier, + type IOperatorDefinition, + type IFunctionHandler, + type ILookupHandler, + type IExpressionOptions, + + Expressionish, + Expressionish as default, +}; \ No newline at end of file diff --git a/src/expressionish/options.ts b/src/expressionish/options.ts new file mode 100644 index 0000000..2bddc1b --- /dev/null +++ b/src/expressionish/options.ts @@ -0,0 +1,103 @@ +export const enum OperatorQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED, + PREBLOCK, + BLOCK +} + +export type IMeta = Record; + +export type IHandleFnc = (options: IEvaluateOptions, meta: IMeta, stack: string[], ...args: unknown[]) => Promise; + +export type IEOLQuantifier = 'keep' | 'remove' | 'space' | 'error'; + +export type IEndOfLine = IEOLQuantifier | ((eol: string) => string); + +export interface IEOLDefinition { + quantifier: IEOLQuantifier | 'transform'; + transform: (char: string) => string; +} + +export interface IRealizedOperator { + signifier: string; + quantifier: OperatorQuantifier + cased: boolean; + defer: boolean; + evaluate: IHandleFnc +} + +export interface IOperatorDefinition { + signifier: string | string[]; + quantifier: OperatorQuantifier; + cased?: boolean; + defer?: boolean; + inverse?: { + signifier?: string | string[]; + evaluate?: IHandleFnc; + }; + evaluate: IHandleFnc; +} + +export interface IOptionsList { + disposition?: 'append' | 'replace'; + items: T; +} + +export interface IFunctionHandler { + defer?: boolean; + stackCheck?: (options: IEvaluateOptions, meta: IMeta, stack: string[]) => Promise; + argsCheck?: IHandleFnc; + evaluate: IHandleFnc; +} + +export type ILookupHandler = (options: IExpressionOptions, meta: IMeta, stack: string[], name: string) => Promise; + +export interface IGroupSignifier { + open: string, + delimiter?: string, + close: string +} + +export interface IQuoteQuantifier { + open: string; + close: string; +} + +export interface IExpressionOptions { + eol?: IEndOfLine; + escapeSignifier?: string; + functionSignifier?: string; + groupSignifier?: 'parens' | 'brackets' | 'curly' | IGroupSignifier; + quotes?: false | 'single' | 'double' | 'both' | IQuoteQuantifier | IQuoteQuantifier[]; + specialSequences?: boolean | IOptionsList>; + comparisonOperators?: boolean | IOptionsList; + blockOperators?: boolean | IOptionsList; + functionHandlers?: boolean | IOptionsList>; + lookupHandlers?: Record; +} + +export interface IEvaluateOptions { + verifyOnly?: boolean; + skipStackChecks?: boolean; + skipArgumentsChecks?: boolean; +} + +export interface IRealizedGroupSignifier { + open: string, + delimiter: string, + close: string +} + +export interface IRealizedOptions { + eol: IEOLDefinition; + escapeSignifier: string; + functionSignifier: string; + groupSignifier: IRealizedGroupSignifier; + quotes: IQuoteQuantifier[]; + specialSequence: Record; + comparisonOperators: Record; + blockOperators: Record; + functionHandlers: Record; + lookupHandler: Record; +} \ No newline at end of file diff --git a/src/expressionish/options/_support.ts b/src/expressionish/options/_support.ts new file mode 100644 index 0000000..b7d5b6a --- /dev/null +++ b/src/expressionish/options/_support.ts @@ -0,0 +1,25 @@ +import isObject from 'src/helpers/is-object'; + +export type RequireAtLeastOne = { [K in keyof T]-?: Required> & Partial>>; }[keyof T] + +export type dispsosition = 'append' | 'override'; + +export interface IQuantifiedList { + disposition?: dispsosition; + items: T; +} + +export const verifyQuantifiedList = (subject: unknown) => { + if (!isObject(subject)) { + throw new Error('TODO'); + } + + const { disposition, items } = >subject; + if (disposition == null || (disposition !== 'append' && disposition !== 'override')) { + throw new Error('TODO'); + } + + if (items == null || (!isObject(items) && !Array.isArray(items))) { + throw new Error('TODO'); + } +} \ No newline at end of file diff --git a/src/expressionish/options/end-of-line.ts b/src/expressionish/options/end-of-line.ts new file mode 100644 index 0000000..9378914 --- /dev/null +++ b/src/expressionish/options/end-of-line.ts @@ -0,0 +1,30 @@ +type IEOLQuantifier = 'keep' | 'remove' | 'space' | 'error'; + +export type IEndOfLineOptions = IEOLQuantifier | ((eol: string) => string); + +export interface IEndOfLineQuantified { + quantifier: IEOLQuantifier | 'transform'; + transform: (char: string) => string; +} + +export default (value: unknown) : IEndOfLineQuantified => { + + if (value === 'error') + return { quantifier: 'error', transform: () => { throw new Error('TODO') } }; + + if (value == null || value === 'keep') + return { quantifier: 'keep', transform: (char) => char }; + + if (value === 'remove') + return { quantifier: 'remove', transform: () => '' }; + + if (value === 'space') + return { quantifier: 'space', transform: () => ' '}; + + if (typeof value === 'function') + return { quantifier: 'transform', transform: value }; + + throw new Error('TODO'); + +}; + diff --git a/src/expressionish/options/function-signifier.ts b/src/expressionish/options/function-signifier.ts new file mode 100644 index 0000000..99369ae --- /dev/null +++ b/src/expressionish/options/function-signifier.ts @@ -0,0 +1,18 @@ +export default (value: unknown, significant: string[]) : string => { + if (value == null) + return '$'; + + if (typeof value !== 'string') + throw new Error('TODO'); + + if (value.length !== 1) + throw new Error('TODO'); + + if (/[!\s'"]/.test(value)) + throw new Error('TODO'); + + if (significant !== null && significant.some(significant => value.includes(significant))) + throw new Error('TODO'); + + return value; +} \ No newline at end of file diff --git a/src/expressionish/options/group-signifier.ts b/src/expressionish/options/group-signifier.ts new file mode 100644 index 0000000..3905655 --- /dev/null +++ b/src/expressionish/options/group-signifier.ts @@ -0,0 +1,57 @@ +interface IGroupSignifier { + open: string, + delimiter?: string, + close: string +} + +export type IGroupSignifierOptions = 'parens' | 'brackets' | 'curly' | IGroupSignifier; + +export interface IGroupSignifierQuantified { + open: string, + delimiter: string, + close: string +} + +export default (value: unknown, significant: string[]) : IGroupSignifierQuantified => { + + if (value == null || value === 'brackets') + return { open: '[', delimiter: ',', close: ']' }; + + if (value === 'parens') + return { open: '(', delimiter: ',', close: ')' }; + + if (value === 'curly') + return { open: '{', delimiter: ',', close: '}' }; + + if (typeof value !== 'object') + throw new Error('TODO'); + + const invalidChars = new RegExp(`[!\\s'"${ + significant + .filter(value => value.length === 1) + .map(value => `\\${value}`) + .join('') + }]`); + + const isValid = (value: unknown) => ( + typeof value === 'string' && + value.length === 1 && + !invalidChars.test(value) + ); + + const { open, delimiter = ',', close } = value; + + if (!isValid(open)) + throw new Error('TODO'); + + if (!isValid(delimiter)) + throw new Error('TODO'); + + if (!isValid(close)) + throw new Error('TODO'); + + if (open === delimiter || delimiter === close || open === close) + throw new Error('TODO'); + + return { open, delimiter, close }; +} \ No newline at end of file diff --git a/src/expressionish/options/operators.ts b/src/expressionish/options/operators.ts new file mode 100644 index 0000000..bfdeeac --- /dev/null +++ b/src/expressionish/options/operators.ts @@ -0,0 +1,208 @@ +import has from '../../helpers/has'; +import isObject from '../../helpers/is-object'; + +import { + type RequireAtLeastOne, + type IQuantifiedList +} from './_support'; + +type IHandleFnc = (...args: unknown[]) => Promise; + +interface IInverseQuantified { + signifier: string | string[]; + evaluate: IHandleFnc; +} +type IInverseOptions = RequireAtLeastOne + +export enum OperatorQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED, + PREBLOCK, + BLOCK +} + +export interface IOperatorOptionsDefinition { + signifier: string | string[]; + quantifier: OperatorQuantifier; + cased?: boolean; + defer?: boolean; + inverse?: boolean | IInverseOptions; + evaluate: IHandleFnc +} + +export type IOperatorOptions = boolean | IQuantifiedList; + +export interface IOperatorQuantified { + signifier: string; + quantifier: OperatorQuantifier; + cased: boolean; + defer: boolean; + evaluate: IHandleFnc +} + +export default ( + signifiers: string[], + registry: Record, + operator: IOperatorOptionsDefinition +) => { + + // helpers + const PROPBASE = { writable: false, enumerable: true, configurable: false }; + const invalidMultis : string[] = []; + const invalidSingles = new RegExp(`[!\\s${ + signifiers.map(value => { + if (value.length === 1) return '\\value'; + if (value.length > 1) invalidMultis.push(value); + }).filter(value => value != null).join('') + }]`); + + + // operator + if (operator == null || !isObject(operator)) { + throw new Error('TODO'); + } + + const { quantifier } = operator + let { signifier, cased, defer, inverse, evaluate } = operator; + + + // operator.signifier + if (signifier == null || signifier === '') { + throw new Error('TODO'); + } else if (typeof signifier === 'string') { + signifier = [signifier]; + } else if (!Array.isArray(signifier)) { + throw new Error('TODO'); + } else if (!signifier.length) { + throw new Error('TODO'); + } + + + // operator.cased + if (typeof cased == null) { + cased = false; + } else if (typeof cased !== 'boolean') { + throw new Error('TODO'); + } + + + // operator.defer + if (typeof defer == null) { + defer = false; + } else if (typeof defer !== 'boolean') { + throw new Error('TODO'); + } + + + // operator.quantifier + if (quantifier == null || !Number.isInteger(quantifier) || !(quantifier in OperatorQuantifier)) { + throw new Error('TODO'); + } + + + // operator.evaluate + if (typeof evaluate !== 'function') { + throw new Error('TODO'); + } + + + // operator.inverse + if (inverse == null) { + inverse = false; + } else if (inverse === true) { + inverse = { + signifier: signifier.map(value => `!${value}`), + evaluate: async (...args: unknown[]) => !(await evaluate(...args)) + }; + } else if (inverse !== false) { + if (!isObject(inverse)) { + throw new Error('TODO'); + } + if (inverse.signifier == null && inverse.evaluate == null) { + throw new Error('TODO'); + } + if (inverse.signifier == null) { + inverse.signifier = signifier.map(value => `!${value}`); + } else if (inverse.signifier === '') { + throw new Error('TODO'); + } else if (typeof inverse.signifier === 'string') { + inverse.signifier = [inverse.signifier]; + } else if (!Array.isArray(inverse.signifier)) { + throw new Error('TODO'); + } else if (!inverse.signifier.length) { + throw new Error('TODO'); + } + + if (inverse.evaluate == null) { + inverse.evaluate = async (...args: unknown[]) => !(await evaluate(...args)) + } else if (typeof inverse.evaluate !== 'function') { + throw new Error('TODO'); + } + } + + + const operators : Record = {}; + + // Realize operators + signifier.forEach(key => { + if (typeof key !== 'string') { + throw new Error('todo'); + } + if ( + key === '' || + invalidSingles.test(key) || + invalidMultis.some(multi => key.includes(multi)) + ) { + throw new Error('TODO'); + } + key = key.toLowerCase(); + if (has(registry, key) || has(operators, key)) { + throw new Error('TODO'); + } + operators[key] = Object.freeze(Object.create(null, { + 'signifier': { ...PROPBASE, value: key }, + 'cased': { ...PROPBASE, value: cased}, + 'defer': { ...PROPBASE, value: defer}, + 'quantifier': { ...PROPBASE, value: quantifier }, + 'evaluate': { ...PROPBASE, value: evaluate } + })); + }); + + if (inverse == null || inverse === false) { + Object.assign(registry, operators); + } + + signifier = (inverse).signifier; + evaluate = (inverse).evaluate; + + (signifier).forEach(key => { + if (typeof key !== 'string') { + throw new Error('todo'); + } + let value = key; + if (key[0] === '!') { + value = key.slice(1); + } + if ( + value === '' || + invalidSingles.test(value) || + invalidMultis.some(multi => value.includes(multi)) + ) { + throw new Error('TODO'); + } + key = key.toLowerCase(); + if (has(registry, key) || has(operators, key)) { + throw new Error('TODO'); + } + operators[key] = Object.freeze(Object.create(null, { + 'signifier': { ...PROPBASE, value: key }, + 'cased': { ...PROPBASE, value: cased}, + 'defer': { ...PROPBASE, value: defer}, + 'quantifier': { ...PROPBASE, value: quantifier }, + 'evaluate': { ...PROPBASE, value: evaluate } + })); + }); + + return Object.assign(registry, operators); +}; \ No newline at end of file diff --git a/src/expressionish/options/quotes-signifiers.ts b/src/expressionish/options/quotes-signifiers.ts new file mode 100644 index 0000000..be6f283 --- /dev/null +++ b/src/expressionish/options/quotes-signifiers.ts @@ -0,0 +1,72 @@ +export interface IQuotesQuantified { + open: string; + close: string; +} + +export type IQuotesOptions = false | 'single' | 'double' | 'both' | IQuotesQuantified | IQuotesQuantified[]; + +export default (value: unknown, significant: string[]) : IQuotesQuantified[] => { + if (value === false) + return []; + + if (value == null || value === 'double') + return [ Object.freeze({open: '"', close: '"'}) ]; + + if (value === 'single') + return [ Object.freeze({ open: "'", close: "'"}) ]; + + if (value === 'both') + return [ + Object.freeze({ open: '"', close: '"'}), + Object.freeze({ open: "'", close: "'"}) + ]; + + if (typeof value !== 'object') + throw new Error('TODO'); + + if (!Array.isArray(value)) + value = [value]; + + const invalidMulti : string[] = []; + const invalidChars = new RegExp(`[!\\s${ + significant + .filter(value => { + if (value.length > 1) { + invalidMulti.push(value); + return false; + } + return value.length === 1; + }) + .map(value => `\\${value}`) + .join('') + }]`); + const inuse : string[] = []; + const isValid = (value: unknown) => ( + typeof value === 'string' && + value.length === 1 && + !invalidChars.test(value) && + !invalidMulti.some(multi => value.includes(multi)) && + !inuse.some(used => used === value) + ); + + return (value) + .filter(value => value != null) + .map(value => { + if (typeof value !== 'object') + throw new Error('TODO'); + + const { open, close } = value; + + if (!isValid(open)) + throw new Error('TODO'); + + if (!isValid(close)) + throw new Error('TODO'); + + inuse.push(open); + if (open !== close) + inuse.push(close); + + return { open, close }; + }); +} \ No newline at end of file diff --git a/src/expressionish/options/special-sequences.ts b/src/expressionish/options/special-sequences.ts new file mode 100644 index 0000000..5487e37 --- /dev/null +++ b/src/expressionish/options/special-sequences.ts @@ -0,0 +1,67 @@ +import has from 'src/helpers/has'; +import isObject from '../../helpers/is-object'; + +import { type IQuantifiedList } from './_support'; + +type ISpecialSequences = IQuantifiedList>; + +export type ISpecialSequencesOptions = boolean | ISpecialSequences; + +export type ISpecialSequencesQuantified = Record; + +const defaultSequences : ISpecialSequencesQuantified = { + 't': '\\t', + 'n': '\\n', + 'r': '\\r' +}; + +export default (value: ISpecialSequencesOptions) : Record => { + if (value === false) + return Object.freeze({}); + + if (value == null || value === true) + return Object.freeze( { ...defaultSequences }); + + if (!isObject(value)) { + throw new Error('TODO'); + } + + const { disposition = 'append', items} = value; + + if (disposition !== 'append' && disposition !== 'override') { + throw new Error('TODO'); + } + if (!isObject(items)) { + throw new Error('TODO'); + } + + const result : ISpecialSequencesQuantified = {}; + + if (disposition === 'append') { + Object + .keys(defaultSequences) + .forEach(key => { + result[key] = defaultSequences[key]; + }); + } + + Object + .keys(items) + .forEach(key => { + if (typeof key !== 'string') + throw new Error('TODO'); + + if (items[key] == null) + throw new Error('TODO'); + + if (typeof items[key] !== 'string') + throw new Error('TODO'); + + if (has(result, key)) + throw new Error('TODO'); + + result[key] = items[key]; + }); + + return Object.freeze(result); +} \ No newline at end of file diff --git a/src/expressionish/options/special-signifier.ts b/src/expressionish/options/special-signifier.ts new file mode 100644 index 0000000..a687c1d --- /dev/null +++ b/src/expressionish/options/special-signifier.ts @@ -0,0 +1,18 @@ +export default (value: unknown) : string => { + if (value == null) + return '\\'; + + if (typeof value !== 'string') + throw new Error('TODO'); + + if (value == '') + throw new Error('TODO'); + + if (value.length !== 1) + throw new Error('TODO'); + + if (/[!\s'"]/.test(value)) + throw new Error('TODO'); + + return value; +} \ No newline at end of file diff --git a/src/helpers/deep-freeze.ts b/src/helpers/deep-freeze.ts new file mode 100644 index 0000000..57e4adf --- /dev/null +++ b/src/helpers/deep-freeze.ts @@ -0,0 +1,17 @@ +import has from './has'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const freeze = (subject: T, deepFreeze = false) : T => { + if (deepFreeze === true && subject != null && typeof subject === 'object') { + for (const key in subject) { + if (!has(subject, key) || subject[key] == null || typeof subject[key] !== 'object') { + continue; + } + freeze(subject[key], true); + } + freeze(subject, true); + } + return subject; +} + +export default freeze; \ No newline at end of file diff --git a/src/helpers/get-potential-tokens.ts b/src/helpers/get-potential-tokens.ts new file mode 100644 index 0000000..7e71765 --- /dev/null +++ b/src/helpers/get-potential-tokens.ts @@ -0,0 +1,141 @@ +import type IPreToken from '../types/pre-token'; +import type ParserOptions from '../types/options'; + +import split from './unicode-safe-split'; + +const isPreLogic = (subject: string, index: number) : boolean => index < 1 ? true : /^\s/.test(subject[index - 1]); + +const isPostLogic = (subject: string, index: number) : boolean => index + 2 >= subject.length ? true : /^\s$/.test(subject[index + 2]); + +/** Split input string into array of potential tokens */ +export default (options: ParserOptions, subject: string) : IPreToken[] => { + + // remove leading and trailing spaces + let startCursor = 0; + while (subject.length && subject[startCursor] === ' ') { + startCursor += 1; + } + let endCursor = subject.length - 1; + while (subject.length && subject[endCursor] === ' ') { + endCursor -= 1; + } + subject = subject.slice(startCursor, endCursor + 1); + + + const result : IPreToken[] = []; + + let textToken : null | {position: number, value: string} = null; + split( + subject, + (subject: string, char: string, position: number) : number | void => { + + // EOL + if (char === '\n' || char === '\r') { + if (options.eol === 'error') { + throw new Error('TODO - SyntaxError: illegal character'); + } + + if (!options.eol || options.eol === 'remove') { + return; + } + + if (textToken) { + result.push(textToken); + textToken = null; + } + + let inc = 0; + if (options.eol === 'space') { + while ( + subject[position + inc + 1] === '\n' || + subject[position + inc + 1] === '\r' + ) { + inc += 1; + } + char = ' '; + } + + result.push({ + position, + value: char + }); + + return inc; + } + + // \\, $ + const nextChar = subject[position + 1]; + if ( + nextChar != null && + nextChar !== '' && + /^\s$/.test(nextChar) && + ( + char === '\\' || + (char === '$' && /^[^a-z\d\\]$/i.test(nextChar)) + ) + ) { + if (textToken !== null) { + result.push(textToken); + textToken = null; + } + result.push({ + position: position, + value: char + }, { + position: position + 1, + value: nextChar + }); + return 1; + } + + // Block Escape, &&, || + const seq = subject.slice(position, position + 2); + if ( + seq === '``' || + ( + (seq === '&&' || seq === '||') && + isPreLogic(subject, position) && + isPostLogic(subject, position) + ) + ) { + if (textToken !== null) { + result.push(textToken); + textToken = null; + } + result.push({ + position: position, + value: subject.slice(position, position + 2) + }); + return 1; + } + + // Non potentially significant characters + if (char[1] || /^[a-z\d]$/i.test(char)) { + if (textToken == null) { + textToken = { + position, + value: char + }; + } else { + textToken.value += char; + } + return; + } + + // All others + if (textToken !== null) { + result.push(textToken); + textToken = null; + } + result.push({ + position: position, + value: char + }); + } + ); + + if (textToken) { + result.push(textToken); + } + return result; +} \ No newline at end of file diff --git a/src/helpers/has.spec.ts b/src/helpers/has.spec.ts new file mode 100644 index 0000000..19d7df9 --- /dev/null +++ b/src/helpers/has.spec.ts @@ -0,0 +1,20 @@ +import has from './has'; + +test('Should return false for nullish values', () => { + // @ts-expect-error: Testing no value + expect(has()).toBe(false); + + // @ts-expect-error: Testing undefined value + expect(has(undefined)).toBe(false); + + // @ts-expect-error: Testing null value + expect(has(null)).toBe(false); +}); + +test('It should return false for prototype members', () => { + expect(has([], 'split')).toBe(false); +}); + +test('It should return true for own members', () => { + expect(has({key: 'value'}, 'key')).toBe(true); +}); \ No newline at end of file diff --git a/src/helpers/has.ts b/src/helpers/has.ts new file mode 100644 index 0000000..7943413 --- /dev/null +++ b/src/helpers/has.ts @@ -0,0 +1,4 @@ +const hasOwnProperty = Object.prototype.hasOwnProperty; + +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +export default (subject: any, key: string) => (subject != null && hasOwnProperty.call(subject, key) && subject[key] !== undefined); \ No newline at end of file diff --git a/src/helpers/is-object.ts b/src/helpers/is-object.ts new file mode 100644 index 0000000..646c1f6 --- /dev/null +++ b/src/helpers/is-object.ts @@ -0,0 +1,9 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default (subject: any) => ( + subject != null && + typeof subject === 'object' && + ( + subject.prototype == null || + subject.prototype === Object.prototype + ) +); \ No newline at end of file diff --git a/src/helpers/is-primitive.spec.ts b/src/helpers/is-primitive.spec.ts new file mode 100644 index 0000000..2f32dd7 --- /dev/null +++ b/src/helpers/is-primitive.spec.ts @@ -0,0 +1,27 @@ +import isPrimitive from './is-primitive'; + +test('Returns true for boolean', () => { + expect(isPrimitive(true)).toBe(true); + expect(isPrimitive(false)).toBe(true); +}); + +test('Returns true for finite numbers, and false for other numbers', () => { + expect(isPrimitive(1)).toBe(true); + expect(isPrimitive(NaN)).toBe(false); + expect(isPrimitive(Infinity)).toBe(false); +}); + +test('Returns true for literal strings, false for instances', () => { + expect(isPrimitive('')).toBe(true); + expect(isPrimitive(new String(''))).toBe(false); +}); + +test('All others should be false', () => { + // @ts-expect-error: Testing empty input + expect(isPrimitive()).toBe(false); + expect(isPrimitive(undefined)).toBe(false); + expect(isPrimitive(null)).toBe(false); + expect(isPrimitive([])).toBe(false); + expect(isPrimitive({})).toBe(false); + expect(isPrimitive(()=>1)).toBe(false); +}); diff --git a/src/helpers/is-primitive.ts b/src/helpers/is-primitive.ts new file mode 100644 index 0000000..a953463 --- /dev/null +++ b/src/helpers/is-primitive.ts @@ -0,0 +1,5 @@ +export default (subject: unknown) : boolean => ( + typeof subject === 'boolean' || + (typeof subject === 'number' && Number.isFinite(subject)) || + typeof subject === 'string' +); \ No newline at end of file diff --git a/src/helpers/misc.js b/src/helpers/misc.js deleted file mode 100644 index 9eaf40a..0000000 --- a/src/helpers/misc.js +++ /dev/null @@ -1,10 +0,0 @@ -const hasOwnProperty = Object.prototype.hasOwnProperty; -module.exports.has = (subject, key) => hasOwnProperty.call(subject, key); - -module.exports.removeWhitespace = tokens => { - let result = ''; - while (tokens.length && tokens[0].value === ' ') { - result += tokens.shift().value; - } - return result; -}; \ No newline at end of file diff --git a/src/helpers/split.js b/src/helpers/split.js deleted file mode 100644 index 04cd4b6..0000000 --- a/src/helpers/split.js +++ /dev/null @@ -1,192 +0,0 @@ -/* -The MIT License (MIT) @ Copyright (c) 2016 Justin Sippel, Vitaly Domnikov -https://github.com/bluelovers/runes/blob/8013b6e4021a41d6b579d76b3332c87389c5f092/LICENSE -*/ -const HIGH_SURROGATE_START = 0xd800; -const HIGH_SURROGATE_END = 0xdbff; -const LOW_SURROGATE_START = 0xdc00; -const REGIONAL_INDICATOR_START = 0x1f1e6; -const REGIONAL_INDICATOR_END = 0x1f1ff; -const FITZPATRICK_MODIFIER_START = 0x1f3fb; -const FITZPATRICK_MODIFIER_END = 0x1f3ff; -const VARIATION_MODIFIER_START = 0xfe00; -const VARIATION_MODIFIER_END = 0xfe0f; -const DIACRITICAL_MARKS_START = 0x20d0; -const DIACRITICAL_MARKS_END = 0x20ff; -const ZWJ = 0x200d; -const GRAPHEMS = new Set([ - 0x0308, // ( ◌̈ ) COMBINING DIAERESIS - 0x0937, // ( ष ) DEVANAGARI LETTER SSA - 0x093F, // ( ि ) DEVANAGARI VOWEL SIGN I - 0x0BA8, // ( ந ) TAMIL LETTER NA - 0x0BBF, // ( ி ) TAMIL VOWEL SIGN I - 0x0BCD, // ( ◌்) TAMIL SIGN VIRAMA - 0x0E31, // ( ◌ั ) THAI CHARACTER MAI HAN-AKAT - 0x0E33, // ( ำ ) THAI CHARACTER SARA AM - 0x0E40, // ( เ ) THAI CHARACTER SARA E - 0x0E49, // ( เ ) THAI CHARACTER MAI THO - 0x1100, // ( ᄀ ) HANGUL CHOSEONG KIYEOK - 0x1161, // ( ᅡ ) HANGUL JUNGSEONG A - 0x11A8 // ( ᆨ ) HANGUL JONGSEONG KIYEOK -]); - -const betweenInclusive = (value, lower, upper) => { - return (value >= lower && value <= upper); -}; - -const codePointFromSurrogatePair = pair => { - const highOffset = pair.charCodeAt(0) - HIGH_SURROGATE_START; - const lowOffset = pair.charCodeAt(1) - LOW_SURROGATE_START; - return (highOffset << 10) + lowOffset + 0x10000; -}; - -const isSignificant = char => ( - char === '"' || - char === '\\' || - char === '$' || - char === '[' || - char === ',' || - char === ']' || - char === ' ' -); - -// Unicode-safe splitting -module.exports.split = string => { - if (typeof string !== 'string') { - throw new Error('string cannot be undefined or null') - } - const result = []; - let idx = 0; - let inc = 0; - while (idx < string.length) { - const idxInc = idx + inc; - const current = string[idxInc]; - if ( - idxInc < (string.length - 1) && - current && - betweenInclusive(current.charCodeAt(0), HIGH_SURROGATE_START, HIGH_SURROGATE_END) - ) { - const currPair = codePointFromSurrogatePair(current + string[idxInc + 1]); - const nextPair = codePointFromSurrogatePair(string.substring(idxInc + 2, idxInc + 5)); - if ( - betweenInclusive(currPair, REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END) && - betweenInclusive(nextPair, REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END) - ) { - inc += 4; - } else if (betweenInclusive(nextPair, FITZPATRICK_MODIFIER_START, FITZPATRICK_MODIFIER_END)) { - inc += 4; - } else { - inc += 2; - } - } else { - inc += 1; - } - if (GRAPHEMS.has((string[idx + inc] + '').charCodeAt(0))) { - inc += 1; - } - if (betweenInclusive((string[idx + inc] + '').charCodeAt(0), VARIATION_MODIFIER_START, VARIATION_MODIFIER_END)) { - inc += 1; - } - if (betweenInclusive((string[idx + inc] + '').charCodeAt(0), DIACRITICAL_MARKS_START, DIACRITICAL_MARKS_END)) { - inc += 1; - } - if ((string[idx + inc] + '').charCodeAt(0) === ZWJ) { - inc += 1; - continue; - } - result.push(string.substring(idx, idx + inc)); - idx += inc; - inc = 0; - } - return result; -}; - -// Unicode safe tokenizer -module.exports.tokenize = input => { - - if (typeof input !== 'string') { - throw new Error('string cannot be undefined or null') - } - - const result = []; - let idx = 0; - let inc = 0; - let tok = null; - while (idx < input.length) { - const idxInc = idx + inc; - const current = input[idxInc]; - if ( - idxInc < (input.length - 1) && - current && - betweenInclusive(current.charCodeAt(0), HIGH_SURROGATE_START, HIGH_SURROGATE_END) - ) { - const currPair = codePointFromSurrogatePair(current + input[idxInc + 1]); - const nextPair = codePointFromSurrogatePair(input.substring(idxInc + 2, idxInc + 5)); - if ( - betweenInclusive(currPair, REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END) && - betweenInclusive(nextPair, REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END) - ) { - inc += 4; - } else if (betweenInclusive(nextPair, FITZPATRICK_MODIFIER_START, FITZPATRICK_MODIFIER_END)) { - inc += 4; - } else { - inc += 2; - } - } else { - inc += 1; - } - if (GRAPHEMS.has((input[idx + inc] + '').charCodeAt(0))) { - inc += 1; - } - if (betweenInclusive((input[idx + inc] + '').charCodeAt(0), VARIATION_MODIFIER_START, VARIATION_MODIFIER_END)) { - inc += 1; - } - if (betweenInclusive((input[idx + inc] + '').charCodeAt(0), DIACRITICAL_MARKS_START, DIACRITICAL_MARKS_END)) { - inc += 1; - } - if ((input[idx + inc] + '').charCodeAt(0) === ZWJ) { - inc += 1; - continue; - } - - // Emoji - if (inc > 1) { - if (tok == null) { - tok = {position: idx, value: ''}; - } - tok.value += input.substring(idx, idx + inc); - - // `` - } else if (input[idx] === '`' && input[idx + 1] === '`') { - if (tok != null) { - result.push(tok); - tok = null; - } - - result.push({position: idx, value: '``'}); - idx += 1; - - // Significant Characters - } else if (isSignificant(input[idx])) { - if (tok != null) { - result.push(tok); - tok = null; - } - result.push({position: idx, value: input[idx] === '\n' ? ' ' : input[idx]}); - - // Non-emoji, Non-significant characters - } else if (tok == null) { - tok = {position: idx, value: input[idx]}; - } else { - tok.value += input[idx]; - } - - idx += inc; - inc = 0; - } - if (tok != null) { - result.push(tok); - } - - return result; -}; \ No newline at end of file diff --git a/src/helpers/to-number.spec.ts b/src/helpers/to-number.spec.ts new file mode 100644 index 0000000..ec7ecd1 --- /dev/null +++ b/src/helpers/to-number.spec.ts @@ -0,0 +1,19 @@ +import toNumber from './to-number'; + +test('Returns null for non-numerics', () => { + //@ts-expect-error: Testing empty input + expect(toNumber()).toBe(null); + expect(toNumber(undefined)).toBe(null); + expect(toNumber(null)).toBe(null); + expect(toNumber('')).toBe(null); + expect(toNumber([])).toBe(null); + expect(toNumber({})).toBe(null); + expect(toNumber(()=>1)).toBe(null); + expect(toNumber(NaN)).toBe(null); + expect(toNumber(Infinity)).toBe(null); +}); + +test('Returns number for numeric', () => { + expect(toNumber(1)).toBe(1); + expect(toNumber('1')).toBe(1); +}) \ No newline at end of file diff --git a/src/helpers/to-number.ts b/src/helpers/to-number.ts new file mode 100644 index 0000000..ea3913b --- /dev/null +++ b/src/helpers/to-number.ts @@ -0,0 +1,13 @@ +export default (subject: unknown) : null | number => { + if ( + subject != null && + typeof subject !== 'object' && + subject !== '' + ) { + subject = Number(subject); + if (Number.isFinite(subject)) { + return subject; + } + } + return null; +} \ No newline at end of file diff --git a/src/helpers/to-text.spec.ts b/src/helpers/to-text.spec.ts new file mode 100644 index 0000000..ad64264 --- /dev/null +++ b/src/helpers/to-text.spec.ts @@ -0,0 +1,20 @@ +import toText from './to-text'; + +test('Nullish values return undefined', () => { + // @ts-expect-error: Testing no input + expect(toText()).toBeUndefined(); + expect(toText(undefined)).toBeUndefined(); + expect(toText(null)).toBeUndefined(); + expect(toText(()=>1)).toBeUndefined(); +}); + +test('Primitive values should get converted to simple text', () => { + expect(toText(true)).toBe('true'); + expect(toText(false)).toBe('false'); + expect(toText(10)).toBe('10'); + expect(toText('text')).toBe('text'); +}); + +test('Object should be converted to json', () => { + expect(toText({})).toBe('{}'); +}); \ No newline at end of file diff --git a/src/helpers/to-text.ts b/src/helpers/to-text.ts new file mode 100644 index 0000000..501f748 --- /dev/null +++ b/src/helpers/to-text.ts @@ -0,0 +1,18 @@ +import isPrimitive from "./is-primitive"; + +export default (subject: unknown) : string | void => { + if ( + subject != null && + typeof subject !== 'function' + ) { + + if (isPrimitive(subject)) { + return String(subject); + } + + const subjectJSON : string = JSON.stringify(subject); + if (subjectJSON != null) { + return subjectJSON; + } + } +}; \ No newline at end of file diff --git a/src/helpers/token-types.js b/src/helpers/token-types.js deleted file mode 100644 index 679f48f..0000000 --- a/src/helpers/token-types.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - TEXT: 'TEXT', - VARIABLE: 'VARIABLE', - IF: 'IF', - LOGICAL: 'LOGICAL', - CONDITION: 'CONDITION', - UNKNOWN: 'UNKNOWN' -}; diff --git a/src/helpers/unicode-safe-split.ts b/src/helpers/unicode-safe-split.ts new file mode 100644 index 0000000..ef4aa03 --- /dev/null +++ b/src/helpers/unicode-safe-split.ts @@ -0,0 +1,104 @@ +/* +The MIT License (MIT) @ Copyright (c) 2016 Justin Sippel, Vitaly Domnikov +https://github.com/bluelovers/runes/blob/8013b6e4021a41d6b579d76b3332c87389c5f092/LICENSE +*/ +export const HIGH_SURROGATE_START = 0xd800; +export const HIGH_SURROGATE_END = 0xdbff; +export const LOW_SURROGATE_START = 0xdc00; +export const REGIONAL_INDICATOR_START = 0x1f1e6; +export const REGIONAL_INDICATOR_END = 0x1f1ff; +export const FITZPATRICK_MODIFIER_START = 0x1f3fb; +export const FITZPATRICK_MODIFIER_END = 0x1f3ff; +export const VARIATION_MODIFIER_START = 0xfe00; +export const VARIATION_MODIFIER_END = 0xfe0f; +export const DIACRITICAL_MARKS_START = 0x20d0; +export const DIACRITICAL_MARKS_END = 0x20ff; +export const ZWJ = 0x200d; +export const GRAPHEMS = new Set([ + 0x0308, // ( ◌̈ ) COMBINING DIAERESIS + 0x0937, // ( ष ) DEVANAGARI LETTER SSA + 0x093F, // ( ि ) DEVANAGARI VOWEL SIGN I + 0x0BA8, // ( ந ) TAMIL LETTER NA + 0x0BBF, // ( ி ) TAMIL VOWEL SIGN I + 0x0BCD, // ( ◌்) TAMIL SIGN VIRAMA + 0x0E31, // ( ◌ั ) THAI CHARACTER MAI HAN-AKAT + 0x0E33, // ( ำ ) THAI CHARACTER SARA AM + 0x0E40, // ( เ ) THAI CHARACTER SARA E + 0x0E49, // ( เ ) THAI CHARACTER MAI THO + 0x1100, // ( ᄀ ) HANGUL CHOSEONG KIYEOK + 0x1161, // ( ᅡ ) HANGUL JUNGSEONG A + 0x11A8 // ( ᆨ ) HANGUL JONGSEONG KIYEOK +]); + +export const betweenInclusive = (value: number, lower: number, upper: number) : boolean => { + return (value >= lower && value <= upper); +}; + +export const codePointFromSurrogatePair = (pair: string) : number => { + const highOffset = pair.charCodeAt(0) - HIGH_SURROGATE_START; + const lowOffset = pair.charCodeAt(1) - LOW_SURROGATE_START; + return (highOffset << 10) + lowOffset + 0x10000; +}; + +/** Splits input text into an array of characters */ +export default ( + subject : string, + callback?: (subject: string, char: string, position: number) => number | void +) : string[] => { + + if (typeof subject !== 'string') { + throw new Error('string cannot be undefined or null') + } + + const result : string[] = []; + let idx = 0; + let inc = 0; + while (idx < subject.length) { + const idxInc = idx + inc; + const current = subject[idxInc]; + if ( + idxInc < (subject.length - 1) && + current && + betweenInclusive(current.charCodeAt(0), HIGH_SURROGATE_START, HIGH_SURROGATE_END) + ) { + const currPair = codePointFromSurrogatePair(current + subject[idxInc + 1]); + const nextPair = codePointFromSurrogatePair(subject.substring(idxInc + 2, idxInc + 5)); + if ( + betweenInclusive(currPair, REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END) && + betweenInclusive(nextPair, REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END) + ) { + inc += 4; + } else if (betweenInclusive(nextPair, FITZPATRICK_MODIFIER_START, FITZPATRICK_MODIFIER_END)) { + inc += 4; + } else { + inc += 2; + } + } else { + inc += 1; + } + if (GRAPHEMS.has((subject[idx + inc] + '').charCodeAt(0))) { + inc += 1; + } + if (betweenInclusive((subject[idx + inc] + '').charCodeAt(0), VARIATION_MODIFIER_START, VARIATION_MODIFIER_END)) { + inc += 1; + } + if (betweenInclusive((subject[idx + inc] + '').charCodeAt(0), DIACRITICAL_MARKS_START, DIACRITICAL_MARKS_END)) { + inc += 1; + } + if ((subject[idx + inc] + '').charCodeAt(0) === ZWJ) { + inc += 1; + continue; + } + const char = subject.substring(idx, idx + inc); + if (callback) { + const cbres = callback(subject, char, idx); + if (cbres != null) { + inc += cbres; + } + } + result.push(char); + idx += inc; + inc = 0; + } + return result; +}; \ No newline at end of file diff --git a/src/helpers/whitespace.spec.ts b/src/helpers/whitespace.spec.ts new file mode 100644 index 0000000..7a65fa1 --- /dev/null +++ b/src/helpers/whitespace.spec.ts @@ -0,0 +1,40 @@ +import { + is, + consume +} from './whitespace'; + +test('Export \'is\' as a function', () => { + expect(typeof is).toBe('function'); +}); + +test('is() returns undefined if token is not whitespace', () => { + expect(is([], 0)).toBe(false) + expect(is([{position: 0, value: ''}], 0)).toBe(false); +}); + +test('is() returns true for whitespace tokens', () => { + expect(is([{position: 0, value: ' '}], 0)).toBe(true); + expect(is([{position: 0, value: '\t'}], 0)).toBe(true); + expect(is([{position: 0, value: '\n'}], 0)).toBe(true); + expect(is([{position: 0, value: '\t'}], 0)).toBe(true); +}); + +test('Export \'consume\' as a function', () => { + expect(typeof consume).toBe('function'); +}); + +test('consume() does not progress cursor for non whitespace', () => { + expect(consume([ + {position: 0, value: 'a'} + ],0)).toBe(0); +}); + +test('consume() progresses beyond whitespace', () => { + expect(consume([ + {position: 0, value: ' '}, + {position: 1, value: '\t'}, + {position: 2, value: '\n'}, + {position: 3, value: '\r'}, + {position: 4, value: 'a'} + ],0)).toBe(4); +}); \ No newline at end of file diff --git a/src/helpers/whitespace.ts b/src/helpers/whitespace.ts new file mode 100644 index 0000000..92eb074 --- /dev/null +++ b/src/helpers/whitespace.ts @@ -0,0 +1,21 @@ +import type IPreToken from '../types/pre-token'; + +export const is = (tokens: IPreToken[], cursor: number) : boolean => { + return ( + cursor < tokens.length && + ( + tokens[cursor].value === ' ' || + tokens[cursor].value === '\t' || + tokens[cursor].value === '\r' || + tokens[cursor].value === '\n' + ) + ); +}; + +export const consume = (tokens: IPreToken[], cursor: number) : number => { + while (is(tokens, cursor)) { + cursor += 1; + } + + return cursor; +} \ No newline at end of file diff --git a/src/helpers/wildcard-to-regexp.js b/src/helpers/wildcard-to-regexp.js deleted file mode 100644 index ca3ac2b..0000000 --- a/src/helpers/wildcard-to-regexp.js +++ /dev/null @@ -1,100 +0,0 @@ -const { split } = require('./split.js'); - -module.exports = (input, caseSensitive) => { - let wc = split(input); - - let isStart = true; - let startAnchor = true; - let endAnchor = true; - let tokenQCount = 0; - let tokenACount = 0; - let pattern = ''; - let idx = 0; - let processTokens = false; - while (idx < wc.length) { - - let char = wc[idx]; - - // Char needs to be escaped - if ( - char === '^' || - char === '.' || - char === '-' || - char === '+' || - char === '\\' || - char === '/' || - char === '|' || - char === '(' || - char === ')' || - char === '[' || - char === ']' || - char === '{' || - char === '}' || - char === '$' - ) { - char = `\\${char}`; - processTokens = true; - - // Wildcard characters - } else if (char === '*') { - tokenACount += 1; - char = null; - - } else if (char === '?') { - tokenQCount += 1; - char = null; - - // Non-special character - } else { - processTokens = true; - } - - const isEnd = (idx + 1) === wc.length; - - if (processTokens || (isEnd && (tokenQCount || tokenACount))) { - let useAstericks = false; - - if (tokenACount) { - if (isStart) { - startAnchor = false; - } else if (isEnd) { - endAnchor = false; - } else { - useAstericks = true; - } - } - - if (useAstericks) { - if (tokenQCount) { - pattern = pattern + '.'.repeat(tokenQCount) + '+'; - } else { - pattern = pattern + '.*'; - } - } else if (tokenQCount) { - pattern = pattern + '.'.repeat(tokenQCount); - } - - if (char != null) { - pattern += char; - } - - tokenQCount = 0; - tokenACount = 0; - isStart = false; - processTokens = false; - } else if (char) { - pattern += char; - } - - idx += 1; - } - - if (startAnchor) { - pattern = '^' + pattern; - } - if (endAnchor) { - pattern = pattern + '$'; - } - let res = new RegExp(pattern, caseSensitive ? '' : 'i'); - return res; -}; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f21c1c5 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,348 @@ +import has from './helpers/has'; + +import tokenize from './parse'; +import Expression from './parse/expression'; +import { type default as Token } from './parse/token'; + +const enum ArgumentType { + VALUE, + CONDITION +} + +const enum ComparisonQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED +} + +const enum ComparisonBlockQuantifier { + PRE, + POST +} + +type IEOLTransformer = (char: string) => Promise; +type IEndOfLine = 'error' | 'remove' | 'space' | 'keep' | IEOLTransformer; + +type disposition = 'append' | 'replace'; + +interface ISpecialSequences { + disposition?: disposition; + sequences: Record; +} + +type IMeta = Record; + +type IEvaluate = (options: IEvaluateOptions, meta: IMeta, ...args: Token[]) => Promise; + +interface IComparisonInverseOperator { + signifier?: string | string[]; + evaluate?: IEvaluate; +} + +interface IComparisonOperator { + signifier: string | string[]; + cased?: boolean; + quantifier: ComparisonQuantifier; + inverse?: boolean | IComparisonInverseOperator; + evaluate: IEvaluate; +} + +interface IBlockOperator extends Omit { + quantifier: ComparisonBlockQuantifier; + defer?: boolean +} + +interface IOperatorOptions { + disposition?: disposition; + operators?: Array; +} + +interface ArgumentsDescriptor { + type: ArgumentType; + multi: boolean; + optional?: boolean; +} + +interface IFunctionHandler { + defer?: boolean; + arguments?: ArgumentsDescriptor[]; + stackCheck?: (options: IEvaluateOptions, meta: IMeta, stack: string[]) => Promise; + argsCheck?: (options: IEvaluateOptions, meta: IMeta, ...args: Token[]) => Promise; + evaluate: (options: IEvaluateOptions, meta: IMeta, ...args: Token[]) => Promise; +} + +type IFunctionHandlers = Record; +type IFunctionLookupHandler = (options: IEvaluateOptions, meta: IMeta, name: string) => Promise; +type IFunctionLookupHandlers = Record; + +interface IExpressionishOptions { + eol?: IEndOfLine; + specialSequences?: boolean | ISpecialSequences; + + comparisonOperators?: boolean | IOperatorOptions; + blockOperators?: boolean | IOperatorOptions; + + functionHandlers?: boolean | IFunctionHandlers; + functionLookupHandlers?: IFunctionLookupHandlers; +} + +interface IEvaluateOptions { + verifyOnly?: boolean; + skipStackChecks?: boolean; + skipArgumentsChecks?: boolean; +} + +const defaultSpecialSequences : Record = { + '\\t': '\t', + '\\n': '\n', + '\\r': '\r' +}; + +interface IExpandedOperator { + signifier: string[]; + cased: boolean; + defer: boolean; + quantifier: T; + inverse: false | { + signifier: string[]; + evaluate: IEvaluate; + }; + evaluate: IEvaluate; +} + +const isArrayOfString = (subject: unknown[]) : boolean => { + if (!Array.isArray(subject)) { + return false; + } + return (>subject).every((value: unknown) => { + return ( + typeof value === 'string' && + value !== '' && + value !== ' ' && + value !== '\t' && + value !== '\n' && + value !== '\r' + ); + }); +}; + +export class Expressionish { + + private eol : IEndOfLine; + private specialSequences : Record; + + private comparisonOperators: Record; + private blockOperators: Record; + + private functionHandlers : IFunctionHandlers; + private functionLookupHandlers : IFunctionLookupHandlers; + + constructor(options: IExpressionishOptions = {}) { + + if (options.eol == null) { + this.eol === 'keep'; + } else { + this.eol = options.eol; + } + + + // special sequences + if (options.specialSequences === false) { + this.specialSequences = {}; + + } else if (options.specialSequences == null || options.specialSequences === true) { + this.specialSequences = { ...defaultSpecialSequences }; + + } else if (options.specialSequences.disposition === 'replace') { + this.specialSequences = { ...(options.specialSequences.sequences)}; + + } else { + this.specialSequences = { ...defaultSpecialSequences, ...(options.specialSequences.sequences) }; + } + + + // comparison operators + this.comparisonOperators = {}; + if ( + options.comparisonOperators == null || + options.comparisonOperators === true || + (>options.comparisonOperators)?.disposition === 'append' + ) { + defaultComparisonOperators.forEach((operator: IComparisonOperator) => { + this.registerComparisonOperator(operator); + }); + } + if ((>options.comparisonOperators)?.operators != null) { + (>options.comparisonOperators)?.operators.forEach((operator: IComparisonOperator) => { + this.registerComparisonOperator(operator); + }); + } + + + // block operators + this.blockOperators = {}; + if ( + options.blockOperators == null || + options.blockOperators === true || + (>options.blockOperators)?.disposition === 'append' + ) { + defaultBlockOperators.forEach((operator: IBlockOperator) => { + this.registerComparisonOperator(operator); + }); + } + if ((>options.blockOperators)?.operators != null) { + (>options.blockOperators)?.operators.forEach((operator: IBlockOperator) => { + this.registerBlockOperator(operator); + }); + } + + + // function handlers + if ( + options.functionHandlers == null || + options.functionHandlers === false + ) { + this.functionHandlers = {}; + + } else if (options.functionHandlers === true) { + // TODO: register $if[] + + } else { + this.functionHandlers = options.functionHandlers; + } + + + // function lookups + if (options.functionLookupHandlers == null) { + this.functionLookupHandlers = {}; + + } else { + this.functionLookupHandlers = options.functionLookupHandlers; + } + } + + + registerSpecialSequence(key: string, value: string) { + if (typeof key !== 'string' || key.length !== 1) { + // error + } else if (key === ' ') { + // error + } else if (typeof value !== 'string' || key.length < 1) { + // error + } else if (has(this.specialSequences, key)) { + // error + } else { + this.specialSequences[key] = value; + } + } + + + registerComparisonOperator(operator: IComparisonOperator) { + + const expandedOperator : Partial> = {}; + + if (typeof operator.signifier === 'string') { + expandedOperator.signifier = [operator.signifier]; + } else if (isArrayOfString(operator.signifier)) { + expandedOperator.signifier = operator.signifier; + } else { + throw new Error('TODO'); + } + + + if (typeof operator.cased == null) { + expandedOperator.cased = false; + } else if (typeof operator.cased !== 'boolean') { + throw new Error('TODO'); + } else { + expandedOperator.cased = operator.cased; + } + + + expandedOperator.defer = false; + + + if ( + operator.quantifier != null && + operator.quantifier !== ComparisonQuantifier.LEFTONLY && + operator.quantifier !== ComparisonQuantifier.RIGHTOPTIONAL && + operator.quantifier !== ComparisonQuantifier.RIGHTREQUIRED + ) { + throw new Error('TODO'); + } + expandedOperator.quantifier = operator.quantifier; + + + const inverse = operator.inverse; + if (inverse == null || inverse === false) { + expandedOperator.inverse = false; + + } else if (inverse !== true && typeof inverse !== 'object') { + throw new Error('TODO'); + + } else { + let signifier : string[]; + let evaluate: IEvaluate; + if (inverse == true || inverse.signifier == null) { + signifier = expandedOperator.signifier.map((signifier: string) => `!${signifier}`); + } else if (typeof inverse.signifier === 'string') { + signifier = [inverse.signifier]; + } else if (isArrayOfString(signifier)) { + signifier = inverse.signifier; + } else { + throw new Error('TODO'); + } + if (inverse == true || inverse.evaluate == null) { + evaluate = async (options: IEvaluateOptions, meta: IMeta, ...args: Token[]) : Promise => { + return !(await operator.evaluate(options, meta, ...args)); + }; + } else if (typeof inverse.evaluate === 'function') { + evaluate = inverse.evaluate; + } else { + throw new Error('TODO'); + } + expandedOperator.inverse = {signifier, evaluate} + } + + if (typeof operator.evaluate !== 'function') { + throw new Error('TODO'); + } else { + expandedOperator.evaluate = operator.evaluate; + } + + for (let idx = 0; idx < expandedOperator.signifier.length; idx += 1) { + const signifier = expandedOperator.signifier[idx].toLowerCase(); + const { cased, quantifier, evaluate } = expandedOperator; + if (has(this.comparisonOperators, signifier)) { + throw new Error('comparison operator already registered'); + } + this.comparisonOperators[signifier] = { signifier, cased, quantifier, evaluate}; + } + + if (expandedOperator.inverse) { + const { cased, quantifier, inverse } = expandedOperator; + for (let idx = 0; idx < inverse.signifier.length; idx += 1) { + const signifier = inverse.signifier[idx].toLowerCase(); + const evaluate = inverse.evaluate; + if (has(this.comparisonOperators, signifier)) { + throw new Error('comparison operator already registered'); + } + this.comparisonOperators[signifier] = { signifier, cased, quantifier, evaluate }; + } + } + } + + registerBlockOperator(operator: IBlockOperator) { + } + registerFunctionHandler(name: string, handler: IFunctionHandler) { + } + registerFunctionLookupHandler(prefix: string, handler: IFunctionLookupHandler) { + } +} + +export { + ExpressionError, + ExpressionArgumentsError, + ExpressionSyntaxError, + ExpressionVariableError +} from './errors'; \ No newline at end of file diff --git a/src/operators/compare.js b/src/operators/compare.js deleted file mode 100644 index a566326..0000000 --- a/src/operators/compare.js +++ /dev/null @@ -1,145 +0,0 @@ -const wildcardToRegExp = require('../helpers/wildcard-to-regexp.js'); - -const isRange = /^((?:[+-]?\d+(?:\.\d+)?)|(?:[+-]?\.\d+))-((?:[+-]?\d+(?:\.\d+)?)|(?:[+-]?\.\d+))$/; - -const toNumber = (v1, v2) => { - if (v1 === '' || v2 === '') { - return [v1, v2]; - } - - const v1Num = Number(v1); - if (Number.isNaN(v1Num)) { - return [v1, v2]; - } - - const v2Num = Number(v2); - if (Number.isNaN(v2Num)) { - return [v1, v2]; - } - return [v1Num, v2Num]; -} - -const isStrictEqual = (v1, v2) => { - return v1 === v2; -}; - -const isLooseEqual = (v1, v2) => { - if (v1 === v2) { - return true; - } - if (v1.toLowerCase() === v2.toLowerCase()) { - return true; - } - const [v1Num, v2Num] = toNumber(v1, v2); - return v1Num === v2Num; -}; - -const exists = (v1) => { - return v1 != null && - v1 !== false && - v1 !== ''; -}; - -const isNumber = (v1, v2) => { - if (v1 === '') { - return false; - } - v1 = Number(v1); - - if (Number.isNaN(v1)) { - return false; - } - if (v2 == null || v2 === '') { - return true; - } - const range = isRange.exec(v2); - - if (!range) { - return false; - } - - let r1 = Number(range[1]), - r2 = Number(range[2]); - - if (r1 > r2) { - return (r2 <= v1 && v1 <= r1); - } - return (r1 <= v1 && v1 <= r2); -}; - -const isRegexMatch = (v1, v2) => { - const parts = /^\/(.*)\/([a-z]*)$/i.exec(v2); - if (parts) { - return (new RegExp(parts[1], parts[2])).test(v1); - } - return (new RegExp(v2)).test(v1); -}; - -const isWildcardMatch = (v1, v2) => { - if (v2 === null || v2 == '') { - return false; - } - return wildcardToRegExp(v2, false).test(v1); -} - -const isWildcardMatchCaseSensitive = (v1, v2) => { - if (v2 === null || v2 == '') { - return false; - } - return wildcardToRegExp(v2, true).test(v1); -}; - -module.exports = new Map([ - ['===', isStrictEqual], - ['!==', (...args) => !(isStrictEqual(...args))], - - ['==', isLooseEqual], - ['!=', (...args) => !(isLooseEqual(...args))], - - ['<', (v1, v2) => { - [v1, v2] = toNumber(v1, v2); - if (typeof v1 !== 'number' || typeof v2 !== 'number') { - return false; - } - return v1 < v2; - }], - ['<=', (v1, v2) => { - [v1, v2] = toNumber(v1, v2); - if (typeof v1 !== 'number' || typeof v2 !== 'number') { - return false; - } - return v1 <= v2; - }], - ['>', (v1, v2) => { - [v1, v2] = toNumber(v1, v2); - if (typeof v1 !== 'number' || typeof v2 !== 'number') { - return false; - } - return v1 > v2; - }], - ['>=', (v1, v2) => { - [v1, v2] = toNumber(v1, v2); - if (typeof v1 !== 'number' || typeof v2 !== 'number') { - return false; - } - return v1 >= v2; - }], - - ['exists', exists], - ['!exists', (...args) => !(exists(...args))], - - ['isnumber', isNumber], - ['isnum', isNumber], - - ['!isnumber', (...args) => !(isNumber(...args))], - ['!isnum', (...args) => !(isNumber(...args))], - - ['regex', isRegexMatch], - ['!regex', (...args) => !(isRegexMatch(...args))], - - ['iswcm', isWildcardMatch], - ['!iswcm', (...args) => !(isWildcardMatch(...args))], - - ['iswcmcs', isWildcardMatchCaseSensitive], - ['!iswcmcs', (...args) => !(isWildcardMatchCaseSensitive(...args))] -]); \ No newline at end of file diff --git a/src/operators/logical.js b/src/operators/logical.js deleted file mode 100644 index 36057c4..0000000 --- a/src/operators/logical.js +++ /dev/null @@ -1,34 +0,0 @@ -const $not = arg => (arg == null || arg === false || arg === ''); - -const $and = (...args) => { - if (!args || !args.length) { - return false; - } - return !args.some(item => $not(item)); -}; - -const $or = (...args) => { - if (!args || !args.length) { - return false; - } - return args.some(item => (item != null && item !== false && item !== '')); -} - -const $nand = (...args) => $not($and(...args)); -const $nor = (...args) => $not($or(...args)); - -module.exports = new Map([ - ['$NOT', $not], - - ['$AND', $and], - ['$ALL', $and], - - ['$OR', $or], - ['$ANY', $or], - - ['$NAND', $nand], - ['$NALL', $nand], - - ['$NOR', $nor], - ['$NANY', $nor] -]); \ No newline at end of file diff --git a/src/parse/argument-list/index.ts b/src/parse/argument-list/index.ts new file mode 100644 index 0000000..7c3473d --- /dev/null +++ b/src/parse/argument-list/index.ts @@ -0,0 +1 @@ +export { default as tokenizeArgumentsList } from './tokenize'; \ No newline at end of file diff --git a/src/parse/argument-list/tokenize/index.ts b/src/parse/argument-list/tokenize/index.ts new file mode 100644 index 0000000..9d6b27e --- /dev/null +++ b/src/parse/argument-list/tokenize/index.ts @@ -0,0 +1,87 @@ +import TokenType from '../../../types/token-types'; +import type ITokenizeState from '../../../types/tokenize-state'; + +import { ExpressionSyntaxError } from '../../../errors'; + +import Token from '../../token'; + +import { tokenizeArgument } from '../../argument'; +import { tokenizeCondition } from '../../condition'; + +export default async (state: ITokenizeState, isCondition = false) : Promise => { + const { stack, options } = state; + let { tokens, cursor } = state; + + if (tokens[cursor]?.value !== '[') { + return false; + } + cursor += 1; + + const args : Token[] = []; + + while ( + cursor < tokens.length && + tokens[cursor].value != ']' + ) { + + while (/^\s$/.test(tokens[cursor].value)) { + cursor += 1; + } + + if (tokens[cursor].value === ']') { + break; + } + + if (tokens[cursor].value === ',') { + args.push(new Token({ + position: cursor, + type: TokenType.EMPTY + })); + cursor += 1; + continue; + } + + const mockState : ITokenizeState = { + options: { ...options }, + tokens, + cursor, + stack: [...stack, args.length] + }; + + if ( + (isCondition && await tokenizeCondition(mockState, true)) || + (!isCondition && await tokenizeArgument(mockState)) + ) { + if (mockState.output) { + args.push(mockState.output); + + } else { + args.push(new Token({ + position: cursor, + type: TokenType.EMPTY + })); + } + tokens = mockState.tokens; + cursor = mockState.cursor; + + } else { + throw new ExpressionSyntaxError('illegal character; expected end of argument', tokens[cursor].position); + } + + isCondition = false; + } + + if (cursor >= tokens.length) { + throw new ExpressionSyntaxError('unexpected end'); + } + + if (tokens[cursor].value !== ']') { + throw new ExpressionSyntaxError('illegal character; expected ]', tokens[cursor].position); + } + + state.tokens = tokens; + state.cursor = cursor + 1; + state.output = args; + + return true; +}; \ No newline at end of file diff --git a/src/parse/argument/index.ts b/src/parse/argument/index.ts new file mode 100644 index 0000000..a6f8d02 --- /dev/null +++ b/src/parse/argument/index.ts @@ -0,0 +1,2 @@ +export { default as tokenizeArgument } from './tokenize'; +export { default as ArgumentToken, type IArgumentToken } from './token'; \ No newline at end of file diff --git a/src/parse/argument/token/index.ts b/src/parse/argument/token/index.ts new file mode 100644 index 0000000..007518b --- /dev/null +++ b/src/parse/argument/token/index.ts @@ -0,0 +1,90 @@ +import type IParseOptions from '../../../types/options'; +import TokenType from '../../../types/token-types'; + +import toText from '../../../helpers/to-text'; + +import Token, { type IToken } from '../../token'; + +export interface IArgumentToken extends IToken { + value: Token[]; +} + +export default class ArgumentToken extends Token { + public value: Token[]; + + constructor(token: IArgumentToken) { + + if (token == null) { + throw new Error('TODO - ExpressionError: token not specified'); + } + if (typeof token !== 'object') { + throw new Error('TODO - ExpressionError: token must be an object'); + } + if (token.value == null) { + throw new Error('TODO - ExpressionError: token list not specified'); + } + if (!Array.isArray(token.value)) { + throw new Error('TODO - ExpressionError: token list must be an array') + } + + super({ + ...token, + type: TokenType.ARGUMENT + }); + } + + toJSON() : Record { + return { + ...(super.toJSON()), + value: this.value.map(value => value.toJSON()) + }; + } + async evaluate(options: IParseOptions, meta: unknown) : Promise { + if (options == null) { + options = {}; + } + if (meta == null) { + meta = {}; + } + + const parts = this.value; + + let res : unknown; + for (let idx = 0; idx < parts.length; idx += 1) { + const value = await parts[idx].evaluate(options, meta); + + if (options.verifyOnly) { + continue; + } + + if (value === undefined) { + continue; + } + + if (res == null) { + res = value; + continue; + } + + const strValue = toText(value); + if (strValue == null) { + continue; + } + + if (typeof res !== 'string') { + const strRes = toText(res); + if (strRes == null) { + res = strValue; + + } else { + res = strRes + strValue; + } + continue; + } + + res += strValue; + } + + return res; + } +} \ No newline at end of file diff --git a/src/parse/argument/tokenize/index.ts b/src/parse/argument/tokenize/index.ts new file mode 100644 index 0000000..14fbbec --- /dev/null +++ b/src/parse/argument/tokenize/index.ts @@ -0,0 +1,146 @@ +import TokenType from '../../../types/token-types'; +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; +import ListToken from '../../list'; +import { + TextToken, + tokenizeEscape, + tokenizeEscapeBlock, + tokenizeQuoted, + tokenizeSpecial +} from '../../text'; + +import { tokenizeIf } from '../../if'; +import { tokenizeFunction } from '../../function'; + +import { ExpressionSyntaxError } from '../../../errors'; + +export default async (state: ITokenizeState) : Promise => { + const { stack, options } = state; + let { tokens, cursor } = state; + + const position = tokens[cursor]?.position; + + let whitespaceStart = 0, + whitespace = ''; + const result : Token[] = []; + while ( + cursor < tokens.length && + tokens[cursor].value !== ',' && + tokens[cursor].value !== ']' + ) { + const lastToken : Token | void = result[result.length - 1]; + + const mockState : ITokenizeState = { + options: { ...options }, + tokens, + cursor, + stack: [...stack] + }; + + if ( + await tokenizeEscape(mockState, ['"', '$', '\\', ',', ']',]) || + await tokenizeEscapeBlock(mockState) || + await tokenizeQuoted(mockState) || + await tokenizeSpecial(mockState) || + await tokenizeIf(mockState) || + await tokenizeFunction(mockState) + ) { + if (mockState.output) { + const output : Token = mockState.output; + + if (lastToken == null) { + result.push(output); + + } else { + + const lastTokenIsText = lastToken != null && lastToken.type === TokenType.TEXT; + const mockTokenIsText = output.type === TokenType.TEXT; + + if (lastTokenIsText) { + lastToken.value += whitespace; + if (mockTokenIsText) { + lastToken.value += output.value; + + } else { + result.push(output); + } + + } else if (mockTokenIsText) { + output.value = `${whitespace}${output.value}`; + result.push(output); + + } else{ + if (whitespace !== '') { + + result.push(new TextToken({ + position: whitespaceStart, + value: whitespace + })); + + result.push(output); + } + } + } + } + whitespaceStart = 0; + whitespace = ''; + + tokens = mockState.tokens; + cursor = mockState.cursor; + + continue; + } + + const value = tokens[cursor].value; + if (value === ' ' || value === '\t' || value === '\n' || value === '\r' ) { + if (whitespaceStart === 0) { + whitespaceStart = cursor; + } + whitespace += value; + + cursor += 1; + + } else if (value !== ',' && value !== ']') { + if (!lastToken) { + result.push(new TextToken({ + position: cursor, + value + })); + + } else if (lastToken.type === TokenType.TEXT) { + lastToken.value += whitespace + value; + + } else { + result.push(new TextToken({ + position: cursor, + value: whitespace + value + })); + } + + whitespaceStart = 0; + whitespace = ''; + + cursor += 1; + } + } + + if (cursor >= tokens.length) { + throw new ExpressionSyntaxError('unexpected end of expression'); + } + + const next = tokens[cursor + 1]; + if (next.value !== ',' && next.value !== ']') { + throw new ExpressionSyntaxError('illegal character', next.position, next.value[0]); + } + + state.tokens = tokens; + state.cursor = cursor; + state.output = new ListToken({ + position, + value: result + }) + + return false; +} \ No newline at end of file diff --git a/src/parse/condition/index.ts b/src/parse/condition/index.ts new file mode 100644 index 0000000..a0bb6fb --- /dev/null +++ b/src/parse/condition/index.ts @@ -0,0 +1,3 @@ +export { default as tokenizeCondition } from './tokenize'; + +export { OperatorToken, type IOperatorToken, type IOperator, ArgumentsQuantifier } from './operators'; \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/index.ts b/src/parse/condition/operators/comparison/index.ts new file mode 100644 index 0000000..74dcb96 --- /dev/null +++ b/src/parse/condition/operators/comparison/index.ts @@ -0,0 +1,58 @@ +import { type default as IParseOptions } from '../../../../types/options'; + +import { type IOperator, type IHandleState } from '../token'; + +import operatorContains from './operators/contains'; +import operatorEqualLoose from './operators/equal-loose'; +import operatorEqualStrict from './operators/equal-strict'; +import operatorExists from './operators/exists'; +import operatorGreaterThanOrEqual from './operators/greater-than-or-equal'; +import operatorGreaterThan from './operators/greater-than'; +import operatorIsBool from './operators/is-bool'; +import operatorIsNull from './operators/is-null'; +import operatorLessThanOrEqual from './operators/less-than-or-equal'; +import operatorLessThan from './operators/less-than'; +import operatorNumerical from './operators/numerical'; +import operatorRegex from './operators/regex'; +import operatorWildcard from './operators/wildcard'; + +const operators : Map = new Map(); +[ + operatorContains, + operatorEqualLoose, + operatorEqualStrict, + operatorExists, + operatorGreaterThan, + operatorGreaterThanOrEqual, + operatorIsBool, + operatorIsNull, + operatorLessThan, + operatorLessThanOrEqual, + operatorNumerical, + operatorRegex, + operatorWildcard +].forEach((operator : IOperator) => { + operator.alias.forEach(alias => { + operators.set(alias, operator); + }); + + if (operator.inverse) { + const opin = operator.inverse; + opin.alias.forEach(alias => { + const base : IOperator = { ...operator, inverse: undefined, ...opin }; + + if (!opin.handle) { + base.handle = async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const result = await operator.handle.call(this, options, meta, state); + if (result != null) { + return !result; + } + }; + } + operators.set(alias, base); + }); + } +}); + + +export default operators; \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/contains/index.spec.ts b/src/parse/condition/operators/comparison/operators/contains/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/contains/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/contains/index.ts b/src/parse/condition/operators/comparison/operators/contains/index.ts new file mode 100644 index 0000000..cc099e8 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/contains/index.ts @@ -0,0 +1,41 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; + +import { type default as IParseOptions } from '../../../../../../types/options'; + +export default { + name: 'contains', + description: "Checks if the left operand contains the right operand", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + cased: true, + alias: ['contains'], + inverse: { + description: "Checks if operands are not loosely equal", + alias: ['!contains'] + }, + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + + const { left, right, caseSensitive = false } = state; + + if (Array.isArray(left)) { + return left.some((left: unknown) => { + if (typeof left === 'string') { + if (typeof right !== 'string') { + return false; + } + if (caseSensitive) { + return left === right; + } + return left.toLowerCase() === right.toLowerCase(); + } + return left === right; + }); + } + + if (typeof left === 'string' && typeof right === 'string') { + if (caseSensitive) { + return left.includes(right); + } + return left.toLowerCase().includes(right.toLowerCase()); + } + } +}; \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/equal-loose/index.spec.ts b/src/parse/condition/operators/comparison/operators/equal-loose/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/equal-loose/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/equal-loose/index.ts b/src/parse/condition/operators/comparison/operators/equal-loose/index.ts new file mode 100644 index 0000000..81d9497 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/equal-loose/index.ts @@ -0,0 +1,41 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; + +import isPrimitive from '../../../../../../helpers/is-primitive'; +import toNumber from '../../../../../../helpers/to-number'; + +export default { + name: 'equals-loose', + description: "Checks if operands are loosely equal", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + alias: ['=='], + inverse: { + description: "Checks if operands are not loosely equal", + alias: ['!='] + }, + handle: async function(options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + + if ( + left === right || + (left == null && right == null) || + (Number.isNaN(left) && Number.isNaN(right)) + ) { + return true; + } + + if (isPrimitive(left) && isPrimitive(right)) { + if (String(left).toLowerCase() === String(right).toLowerCase()) { + return true; + } + + const leftNum = toNumber(left); + const rightNum = toNumber(right); + + if (leftNum != null && rightNum != null) { + return leftNum === rightNum; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/equal-strict/index.spec.ts b/src/parse/condition/operators/comparison/operators/equal-strict/index.spec.ts new file mode 100644 index 0000000..fbb207e --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/equal-strict/index.spec.ts @@ -0,0 +1,26 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); + +test('Returns true for strictly equal values', async () => { + expect(await operator.handle({}, {}, { caseSensitive: false, left: false, right: false })).toBe(true); + expect(await operator.handle({}, {}, { caseSensitive: false, left: true, right: true })).toBe(true); + expect(await operator.handle({}, {}, { caseSensitive: false, left: 1, right: 1 })).toBe(true); + expect(await operator.handle({}, {}, { caseSensitive: false, left: null, right: undefined })).toBe(true); + expect(await operator.handle({}, {}, { caseSensitive: false, left: NaN, right: NaN })).toBe(true); + + const value = {}; + expect(await operator.handle({}, {}, { caseSensitive: false, left: value, right: value})).toBe(true); +}); + +test('Returns false when in-equal', async () => { + expect(await operator.handle({}, {}, { caseSensitive: false, left: true, right: false })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: null, right: 'null' })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: null, right: '' })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: 1, right: '1' })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: {}, right: {} })).toBe(false); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/equal-strict/index.ts b/src/parse/condition/operators/comparison/operators/equal-strict/index.ts new file mode 100644 index 0000000..4d26405 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/equal-strict/index.ts @@ -0,0 +1,21 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; + +export default { + name: 'equal-strict', + description: "Checks if operands are strictly equal", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + alias: ['==='], + inverse: { + description: "Checks if operands are not strictly equal", + alias: ['!=='] + }, + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + return ( + left === right || + (left == null && right == null) || + (Number.isNaN(left) && Number.isNaN(right)) + ); + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/exists/index.spec.ts b/src/parse/condition/operators/comparison/operators/exists/index.spec.ts new file mode 100644 index 0000000..914de72 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/exists/index.spec.ts @@ -0,0 +1,15 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); + +test('Returns truthy when value is not falsey', async () => { + expect(await operator.handle({}, {}, { caseSensitive: false, left: undefined })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: null })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: false })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: '' })).toBe(false); + expect(await operator.handle({}, {}, { caseSensitive: false, left: 'test' })).toBe(true); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/exists/index.ts b/src/parse/condition/operators/comparison/operators/exists/index.ts new file mode 100644 index 0000000..0a8896d --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/exists/index.ts @@ -0,0 +1,16 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; + +export default { + name: 'exists', + description: "Checks if operands are strictly equal", + quantifier: ArgumentsQuantifier.LEFTONLY, + alias: ['exists'], + inverse: { + description: "Checks if operands are not strictly equal", + alias: ['!exists'] + }, + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + return state.left != null && state.left !== false && state.left !== ''; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/greater-than-or-equal/index.spec.ts b/src/parse/condition/operators/comparison/operators/greater-than-or-equal/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/greater-than-or-equal/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/greater-than-or-equal/index.ts b/src/parse/condition/operators/comparison/operators/greater-than-or-equal/index.ts new file mode 100644 index 0000000..a8b91db --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/greater-than-or-equal/index.ts @@ -0,0 +1,24 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import toNumber from '../../../../../../helpers/to-number'; + +export default { + name: "greater-than-or-equal", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + description: "Checks if the left operand is numerical and greater than or equal to the right operand", + alias: ['>='], + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + const leftNum = toNumber(left); + if (leftNum == null) { + return; + } + + const rightNum = toNumber(right); + if (rightNum == null) { + return; + } + + return leftNum >= rightNum; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/greater-than/index.spec.ts b/src/parse/condition/operators/comparison/operators/greater-than/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/greater-than/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/greater-than/index.ts b/src/parse/condition/operators/comparison/operators/greater-than/index.ts new file mode 100644 index 0000000..72d047d --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/greater-than/index.ts @@ -0,0 +1,24 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import toNumber from '../../../../../../helpers/to-number'; + +export default { + name: "greater-than", + description: "Checks if the left operand is numerical and greater than to the right operand", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + alias: ['>='], + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + const leftNum = toNumber(left); + if (leftNum == null) { + return; + } + + const rightNum = toNumber(right); + if (rightNum == null) { + return; + } + + return leftNum > rightNum; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/is-bool/index.spec.ts b/src/parse/condition/operators/comparison/operators/is-bool/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/is-bool/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/is-bool/index.ts b/src/parse/condition/operators/comparison/operators/is-bool/index.ts new file mode 100644 index 0000000..8d13d1d --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/is-bool/index.ts @@ -0,0 +1,46 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; + +const toBool = (subject: unknown) => { + if (subject === true || subject === false) { + return subject; + } + + if (typeof subject === 'string') { + const subjectStr = subject.toLowerCase(); + if (subjectStr === 'true') { + return true; + } + if (subjectStr === 'false') { + return true; + } + } +} + +export default { + name: "isbool", + quantifier: ArgumentsQuantifier.LEFTONLY, + description: "Checks if the left operand is boolean and if specified matches the right operand", + alias: ['isbool'], + inverse: { + description: "Checks if the left operand is not a boolean or if specified does not match right operand", + alias: ['!isbool'] + }, + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + + const leftBool = toBool(left); + if (leftBool == null) { + return false; + } + + if (right == null) { + return true; + } + + const rightBool = toBool(right); + if (right != null) { + return leftBool === rightBool; + } + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/is-null/index.spec.ts b/src/parse/condition/operators/comparison/operators/is-null/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/is-null/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/is-null/index.ts b/src/parse/condition/operators/comparison/operators/is-null/index.ts new file mode 100644 index 0000000..8fb9aa1 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/is-null/index.ts @@ -0,0 +1,17 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; + +export default { + name: 'isnull', + description: "Checks if the left operand is null or undefined", + quantifier: ArgumentsQuantifier.LEFTONLY, + alias: ['isnull'], + inverse: { + description: "Checks if the left operand is not null or undefined", + alias: ['!isnull'] + }, + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left } = state; + return left == null; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/less-than-or-equal/index.spec.ts b/src/parse/condition/operators/comparison/operators/less-than-or-equal/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/less-than-or-equal/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/less-than-or-equal/index.ts b/src/parse/condition/operators/comparison/operators/less-than-or-equal/index.ts new file mode 100644 index 0000000..c4348a1 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/less-than-or-equal/index.ts @@ -0,0 +1,25 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import toNumber from '../../../../../../helpers/to-number'; + +export default { + name: 'less-than-or-equal', + description: "Checks if the left operand is numerical and less than or equal to the right operand", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + alias: ['<='], + handle: async function(options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + + const leftNum = toNumber(left); + if (leftNum == null) { + return; + } + + const rightNum = toNumber(right); + if (rightNum == null) { + return; + } + + return leftNum <= rightNum; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/less-than/index.spec.ts b/src/parse/condition/operators/comparison/operators/less-than/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/less-than/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/less-than/index.ts b/src/parse/condition/operators/comparison/operators/less-than/index.ts new file mode 100644 index 0000000..8c741f4 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/less-than/index.ts @@ -0,0 +1,25 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import toNumber from '../../../../../../helpers/to-number'; + +export default { + name: 'less-than', + description: "Checks if the left operand is numerical and less than the right operand", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + alias: ['<'], + handle: async function(options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + + const leftNum = toNumber(left); + if (leftNum == null) { + return; + } + + const rightNum = toNumber(right); + if (rightNum == null) { + return; + } + + return leftNum <= rightNum; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/numerical/index.spec.ts b/src/parse/condition/operators/comparison/operators/numerical/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/numerical/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/numerical/index.ts b/src/parse/condition/operators/comparison/operators/numerical/index.ts new file mode 100644 index 0000000..8d157ee --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/numerical/index.ts @@ -0,0 +1,49 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import toNumber from '../../../../../../helpers/to-number'; + +const isRange = /^((?:[+-]?\d+(?:\.\d+)?)|(?:[+-]?\.\d+))-((?:[+-]?\d+(?:\.\d+)?)|(?:[+-]?\.\d+))$/; + +export default { + name: 'numerical', + quantifier: ArgumentsQuantifier.RIGHTOPTIONAL, + description: "Checks if the left operand is numerical and if specified within the range of the right operand (inclusive)", + alias: ['isnum', 'isnumber'], + inverse: { + description: "Checks if the left operand is not numerical and if specified not within the range of the right operand (inclusive)", + alias: ['!isnum', '!isnumber'] + }, + handle: async function(options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + + const v1 = toNumber(left); + if (v1 == null) { + return false; + } + if (right == null) { + return true; + } + + if (right == null || right === '') { + return true; + } + + if (typeof right != 'string') { + return v1 === right; + } + + const range = isRange.exec(right); + if (!range) { + return; + } + + const r1 = Number(range[1]); + const r2 = Number(range[2]); + + if (r1 > r2) { + return r2 <= v1 && v1 <= r1; + } + + return r1 <= v1 && v1 <= r2; + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/regex/index.spec.ts b/src/parse/condition/operators/comparison/operators/regex/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/regex/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/regex/index.ts b/src/parse/condition/operators/comparison/operators/regex/index.ts new file mode 100644 index 0000000..27a8914 --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/regex/index.ts @@ -0,0 +1,37 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import toText from '../../../../../../helpers/to-text'; + +export default { + name: 'regex', + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + description: "Checks if the left operand is a match of the right operand regex", + alias: ['regex'], + inverse: { + description: "Checks if the left operand is not a match of the right operand regex", + alias: ['!regex'] + }, + handle: async function(options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right } = state; + + if (left == null || typeof right !== 'string') { + return; + } + + const leftText = toText(left); + if (leftText == null) { + return false; + } + + const rightText = toText(right); + if (rightText == null) { + return false; + } + + const parts = /^\/(.*)\/([a-z]*)$/i.exec(rightText); + if (parts) { + return (new RegExp(parts[1], parts[2])).test(leftText); + } + return (new RegExp(rightText)).test(leftText); + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/wildcard/index.spec.ts b/src/parse/condition/operators/comparison/operators/wildcard/index.spec.ts new file mode 100644 index 0000000..67e3ebb --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/wildcard/index.spec.ts @@ -0,0 +1,7 @@ +import '../../../../../../../jest/helpers'; + +import operator from './index'; + +test('Exports an operator definition', () => { + expect(operator).toBeAnOperator(); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/comparison/operators/wildcard/index.ts b/src/parse/condition/operators/comparison/operators/wildcard/index.ts new file mode 100644 index 0000000..4973cfa --- /dev/null +++ b/src/parse/condition/operators/comparison/operators/wildcard/index.ts @@ -0,0 +1,124 @@ +import { type IOperator, type IHandleState, ArgumentsQuantifier } from '../../../token'; +import { type default as IParseOptions } from '../../../../../../types/options'; +import split from '../../../../../../helpers/unicode-safe-split'; +import toText from '../../../../../../helpers/to-text'; + +const toRegExp = (subject: string, caseSensitive: boolean) : RegExp => { + const wc = split(subject); + let pattern = ''; + let anchorStart = true; + let anchorEnd = true; + let idx = 0; + const len = wc.length; + while (idx < len) { + + const atStart = idx === 0; + + let hasTokens = false; + let zeroOrMore = false; + let anyOneChar = 0; + + let char = wc[idx]; + while (char === '?' || char === '*') { + hasTokens = true; + if (wc[idx] === '?') { + anyOneChar += 1; + } else { + zeroOrMore = true; + } + idx += 1; + char = wc[idx]; + } + + if (hasTokens) { + pattern += '.'.repeat(anyOneChar); + if (zeroOrMore) { + const atEnd = idx === len; + + if (atStart) { + anchorStart = false; + } + if (atEnd) { + anchorEnd = false; + } + + if (!atStart && !atEnd) { + if (!anyOneChar) { + pattern += '.*'; + } else { + pattern += '+'; + } + } + } + continue; + } + + // Char needs to be escaped + if ( + char === '^' || + char === '.' || + char === '-' || + char === '+' || + char === '\\' || + char === '/' || + char === '|' || + char === '(' || + char === ')' || + char === '[' || + char === ']' || + char === '{' || + char === '}' || + char === '$' + ) { + pattern += `\\${char}`; + idx += 1; + continue; + } + + pattern += char; + idx += 1; + } + + if (anchorStart) { + pattern = '^' + pattern; + } + if (anchorEnd) { + pattern += '$'; + } + return new RegExp( + pattern, + 'u' + (!caseSensitive ? 'i' : '') + ); +}; + +export default { + name: 'wildcard', + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + description: "Checks if the left operand is a match of the right operand wildcard", + alias: ['iswm'], + cased: true, + inverse: { + description: "Checks if the left operand is not a match of the right operand wildcard", + alias: ['!iswm'] + }, + handle: async function (options: IParseOptions, meta: unknown, state: IHandleState) : Promise { + const { left, right, caseSensitive = false } = state; + + const leftText = toText(left); + if (leftText == null) { + return; + } + + const rightText = toText(right); + if (rightText == null) { + return; + } + + const v2RegExp = toRegExp(rightText, caseSensitive); + if (v2RegExp == null) { + return; + } + + return v2RegExp.test(leftText); + } +} \ No newline at end of file diff --git a/src/parse/condition/operators/index.ts b/src/parse/condition/operators/index.ts new file mode 100644 index 0000000..6063a5f --- /dev/null +++ b/src/parse/condition/operators/index.ts @@ -0,0 +1,6 @@ +export { default as comparisonOperators } from './comparison'; +export { default as logicalOperators } from './logical'; + +export { notOperator } from './logical' + +export { default as OperatorToken, type IOperatorToken, type IOperator, ArgumentsQuantifier } from './token'; \ No newline at end of file diff --git a/src/parse/condition/operators/logical/index.spec.ts b/src/parse/condition/operators/logical/index.spec.ts new file mode 100644 index 0000000..648f60c --- /dev/null +++ b/src/parse/condition/operators/logical/index.spec.ts @@ -0,0 +1,22 @@ +import notOperatorDef from './operators/not'; +import andOperatorDef from './operators/and'; +import orOperatorDef from './operators/or'; +import { notOperator, default as operatorMap } from './index'; + +test('Exports default as map instance', () => { + expect(operatorMap).toBeInstanceOf(Map); +}); + +test('Exports not operator', () => { + expect(notOperator === notOperatorDef).toBe(true); +}); + +test('Addresses \'and\' operator as &&', () => { + expect(operatorMap.has('&&')).toBe(true); + expect(operatorMap.get('&&') === andOperatorDef).toBe(true); +}); + +test('Addresses \'or\' operator as ||', () => { + expect(operatorMap.has('||')).toBe(true); + expect(operatorMap.get('||') === orOperatorDef).toBe(true); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/logical/index.ts b/src/parse/condition/operators/logical/index.ts new file mode 100644 index 0000000..2a19aea --- /dev/null +++ b/src/parse/condition/operators/logical/index.ts @@ -0,0 +1,9 @@ +import operatorAnd from './operators/and'; +import operatorOr from './operators/or'; + +export { default as notOperator } from './operators/not'; + +export default new Map([ + ['&&', operatorAnd], + ['||', operatorOr] +]); \ No newline at end of file diff --git a/src/parse/condition/operators/logical/operators/and.spec.ts b/src/parse/condition/operators/logical/operators/and.spec.ts new file mode 100644 index 0000000..1d3dddf --- /dev/null +++ b/src/parse/condition/operators/logical/operators/and.spec.ts @@ -0,0 +1,92 @@ +import '../../../../../../jest/helpers'; +import Token from '../../../../token'; + +import andOperator from './and'; + +test('Exports an operator definition', () => { + expect(andOperator).toBeAnOperator(); +}); + +test('Returns false when first arg is false', async () => { + + const left = new Token(); + let leftCalled = 0; + left.evaluate = async () => { + leftCalled += 1; + return false; + }; + + const right = new Token(); + let rightCalled = 0; + right.evaluate = async () => { + rightCalled += 1; + return false; + }; + + expect.assertions(3); + + const result = await andOperator.handle({}, {}, { + caseSensitive: false, + arguments: [left, right] + }); + + expect(result).toBe(false); + expect(leftCalled).toBe(1); + expect(rightCalled).toBe(0); +}); + +test('Returns false when second arg is false', async () => { + + const left = new Token(); + let leftCalled = 0; + left.evaluate = async () => { + leftCalled += 1; + return true; + }; + + const right = new Token(); + let rightCalled = 0; + right.evaluate = async () => { + rightCalled += 1; + return false; + }; + + expect.assertions(3); + + const result = await andOperator.handle({}, {}, { + caseSensitive: false, + arguments: [left, right] + }); + + expect(result).toBe(false); + expect(leftCalled).toBe(1); + expect(rightCalled).toBe(1); +}); + +test('Returns true when both args are true', async () => { + + const left = new Token(); + let leftCalled = 0; + left.evaluate = async () => { + leftCalled += 1; + return true; + }; + + const right = new Token(); + let rightCalled = 0; + right.evaluate = async () => { + rightCalled += 1; + return true; + }; + + expect.assertions(3); + + const result = await andOperator.handle({}, {}, { + caseSensitive: false, + arguments: [left, right] + }); + + expect(result).toBe(true); + expect(leftCalled).toBe(1); + expect(rightCalled).toBe(1); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/logical/operators/and.ts b/src/parse/condition/operators/logical/operators/and.ts new file mode 100644 index 0000000..5c4b6de --- /dev/null +++ b/src/parse/condition/operators/logical/operators/and.ts @@ -0,0 +1,21 @@ +import { type default as IParseOptions } from '../../../../../types/options'; +import { type IOperator, type IHandleStateDeferred, ArgumentsQuantifier } from '../../token'; + +export default { + name: 'logical-and', + description: "Checks if two conditions are truthy", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + defer: true, + alias: ['&&'], + handle: async function (options: IParseOptions, meta: unknown, state: IHandleStateDeferred) : Promise { + const { arguments: args } = state; + + const left = await args[0].evaluate(options, meta); + if (left == null || left === false || left === 0 || left === '') { + return false; + } + + const right = await args[1].evaluate(options, meta); + return (right != null && right !== false && right !== 0 && right !== ''); + } +}; \ No newline at end of file diff --git a/src/parse/condition/operators/logical/operators/not.spec.ts b/src/parse/condition/operators/logical/operators/not.spec.ts new file mode 100644 index 0000000..ba241d8 --- /dev/null +++ b/src/parse/condition/operators/logical/operators/not.spec.ts @@ -0,0 +1,46 @@ +import '../../../../../../jest/helpers'; +import Token from '../../../../token'; + +import notOperator from './not'; + +test('Exports an operator definition', () => { + expect(notOperator).toBeAnOperator(); +}); + +test('Returns false when arg is truthy', async () => { + let argCalls = 0; + const arg = new Token(); + arg.evaluate = async () => { + argCalls += 1; + return true; + }; + + expect.assertions(2); + + const result = await notOperator.handle({}, {}, { + caseSensitive: false, + arguments: [arg] + }); + + expect(result).toBe(false); + expect(argCalls).toBe(1); +}); + +test('Returns true when arg is falsey', async () => { + let argCalls = 0; + const arg = new Token(); + arg.evaluate = async () => { + argCalls += 1; + return false; + }; + + expect.assertions(2); + + const result = await notOperator.handle({}, {}, { + caseSensitive: false, + arguments: [arg] + }); + + expect(result).toBe(true); + expect(argCalls).toBe(1); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/logical/operators/not.ts b/src/parse/condition/operators/logical/operators/not.ts new file mode 100644 index 0000000..060a22a --- /dev/null +++ b/src/parse/condition/operators/logical/operators/not.ts @@ -0,0 +1,16 @@ +import { type default as IParseOptions } from '../../../../../types/options'; +import { type IOperator, type IHandleStateDeferred, ArgumentsQuantifier } from '../../token'; + +export default { + name: 'logical-not', + description: "Checks if two conditions are truthy", + quantifier: ArgumentsQuantifier.LEFTONLY, + defer: true, + alias: [], + handle: async function (options: IParseOptions, meta: unknown, state: IHandleStateDeferred) : Promise { + const { arguments: args } = state; + + const left = await args[0].evaluate(options, meta); + return (left == null || left === false || left === 0 || left === ''); + } +}; \ No newline at end of file diff --git a/src/parse/condition/operators/logical/operators/or.spec.ts b/src/parse/condition/operators/logical/operators/or.spec.ts new file mode 100644 index 0000000..f914af4 --- /dev/null +++ b/src/parse/condition/operators/logical/operators/or.spec.ts @@ -0,0 +1,92 @@ +import '../../../../../../jest/helpers'; +import Token from '../../../../token'; + +import orOperator from './or'; + +test('Exports an operator definition', () => { + expect(orOperator).toBeAnOperator(); +}); + +test('Returns true when first arg is true', async () => { + + const left = new Token(); + let leftCalled = 0; + left.evaluate = async () => { + leftCalled += 1; + return true; + }; + + const right = new Token(); + let rightCalled = 0; + right.evaluate = async () => { + rightCalled += 1; + return true; + }; + + expect.assertions(3); + + const result = await orOperator.handle({}, {}, { + caseSensitive: false, + arguments: [left, right] + }); + + expect(result).toBe(true); + expect(leftCalled).toBe(1); + expect(rightCalled).toBe(0); +}); + +test('Returns true when second arg is true', async () => { + + const left = new Token(); + let leftCalled = 0; + left.evaluate = async () => { + leftCalled += 1; + return false; + }; + + const right = new Token(); + let rightCalled = 0; + right.evaluate = async () => { + rightCalled += 1; + return true; + }; + + expect.assertions(3); + + const result = await orOperator.handle({}, {}, { + caseSensitive: false, + arguments: [left, right] + }); + + expect(result).toBe(true); + expect(leftCalled).toBe(1); + expect(rightCalled).toBe(1); +}); + +test('Returns false when both args are false', async () => { + + const left = new Token(); + let leftCalled = 0; + left.evaluate = async () => { + leftCalled += 1; + return false; + }; + + const right = new Token(); + let rightCalled = 0; + right.evaluate = async () => { + rightCalled += 1; + return false; + }; + + expect.assertions(3); + + const result = await orOperator.handle({}, {}, { + caseSensitive: false, + arguments: [left, right] + }); + + expect(result).toBe(false); + expect(leftCalled).toBe(1); + expect(rightCalled).toBe(1); +}); \ No newline at end of file diff --git a/src/parse/condition/operators/logical/operators/or.ts b/src/parse/condition/operators/logical/operators/or.ts new file mode 100644 index 0000000..c6f1450 --- /dev/null +++ b/src/parse/condition/operators/logical/operators/or.ts @@ -0,0 +1,21 @@ +import { type default as IParseOptions } from '../../../../../types/options'; +import { type IOperator, type IHandleStateDeferred, ArgumentsQuantifier } from '../../token'; + +export default { + name: 'logical-or', + description: "Checks if two conditions are truthy", + quantifier: ArgumentsQuantifier.RIGHTREQUIRED, + defer: true, + alias: ['||'], + handle: async function (options: IParseOptions, meta: unknown, state: IHandleStateDeferred) : Promise { + const { arguments: args } = state; + + const left = await args[0].evaluate(options, meta); + if (left != null && left !== false && left !== 0 && left !== '') { + return true; + } + + const right = await args[1].evaluate(options, meta); + return (right != null && right !== false && right !== 0 && right !== ''); + } +}; \ No newline at end of file diff --git a/src/parse/condition/operators/token/index.ts b/src/parse/condition/operators/token/index.ts new file mode 100644 index 0000000..1c6e8a5 --- /dev/null +++ b/src/parse/condition/operators/token/index.ts @@ -0,0 +1,152 @@ +import type IParseOptions from '../../../../types/options'; +import TokenType from '../../../../types/token-types'; + +import { default as Token, type IToken } from '../../../token'; + +interface IHandleStateBase { + caseSensitive: boolean; +} +interface IHandleStateNotDeferred extends IHandleStateBase { + left: unknown; + right?: unknown; + arguments?: never; +} +export interface IHandleStateDeferred extends IHandleStateBase { + left?: never; + right?: never; + arguments: Token[] +} +export type IHandleState = IHandleStateNotDeferred | IHandleStateDeferred; + +export const enum ArgumentsQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED +} + +export type IHandleFn = (options: IParseOptions, meta: unknown, state: IHandleState) => Promise; + +export interface IOperator { + name: string; + description: string; + quantifier: ArgumentsQuantifier; + defer?: boolean; + cased?: boolean, + alias: string[]; + inverse?: { + description: string; + alias: string[]; + handle?: IHandleFn; + }; + handle: IHandleFn; +} + +export interface IOperatorToken extends IToken { + caseSensitive?: boolean; + quantifier: ArgumentsQuantifier; + arguments: Token[]; + defer?: boolean; + handle: IHandleFn; +} + +export default class OperatorToken extends Token { + public quantifier: ArgumentsQuantifier; + public arguments: Token[]; + public defer: boolean; + public caseSensitive : boolean; + public handle : IHandleFn; + + constructor(token: IOperatorToken) { + if (token == null) { + throw new Error('TODO - ExpressionError: token must not be nullish'); + } + + if (token.quantifier == null) { + throw new Error('TODO - ExpressionError: arguments quantifier not specified'); + } + if (!Number.isFinite(token.quantifier)) { + throw new Error('TODO - ExpressionError: must be a number'); + } + + if (token.arguments == null) { + throw new Error('TODO - ExpressionError: arguments list not specified'); + } + if (!Array.isArray(token.arguments)) { + throw new Error('TODO - ExpressionError: arguments list must be an array') + } + if (token.arguments.length === 0) { + throw new Error('TODO - ExpressionError: at least one argument is required'); + } + if (token.arguments.length > 2) { + throw new Error('TODO - ExpressionError: too many arguments specified') + } + if (token.arguments.length !== 2 && token.quantifier === ArgumentsQuantifier.RIGHTREQUIRED) { + throw new Error('TODO - ExpressionError: right argument required'); + } + + if (token.defer != null && token.defer !== false && token.defer !== true) { + throw new Error('TODO - ExpressionError: if specified defer must be boolean'); + } + + if (token.caseSensitive != null && token.caseSensitive !== false && token.caseSensitive !== true) { + throw new Error('TODO - ExpressionError: if specified caseSensitive must be boolean'); + } + + if (token.handle == null) { + throw new Error('TODO - ExpressionError: handle function not specified'); + } + if ( + typeof token.handle !== 'function' && + //eslint-disable-next-line @typescript-eslint/no-explicit-any + token.handle instanceof Function + ) { + throw new Error('TODO - ExpressionError: specified handle must be a function'); + } + + super({ + ...token, + type: TokenType.OPERATOR + }); + + this.quantifier = token.quantifier; + this.arguments = [ ...(token.arguments) ]; + this.defer = token.defer === true; + this.caseSensitive = token.caseSensitive === true; + this.handle = token.handle; + } + + toJSON() : Record { + return { + ...(super.toJSON()), + caseSensitive: this.caseSensitive, + arguments: this.arguments.map(token => token.toJSON()) + }; + } + + async evaluate(options: IParseOptions, meta: unknown): Promise { + if (this.defer) { + if (options.verifyOnly) { + await this.arguments[0].evaluate(options, meta); + if (this.arguments.length > 1) { + await this.arguments[1].evaluate(options, meta); + } + return false; + } + + return await this.handle.call(this, options, meta, {caseSensitive: this.caseSensitive, arguments: this.arguments}); + } + + const left = await this.arguments[0].evaluate(options, meta); + + let right: unknown; + if (this.arguments.length > 1) { + right = await this.arguments[1].evaluate(options, meta); + } + + if (options.verifyOnly) { + return false; + } + + return true === await this.handle.call(this, options, meta, {left, right, caseSensitive: this.caseSensitive}); + } +} \ No newline at end of file diff --git a/src/parse/condition/tokenize/block.ts b/src/parse/condition/tokenize/block.ts new file mode 100644 index 0000000..b28b0cc --- /dev/null +++ b/src/parse/condition/tokenize/block.ts @@ -0,0 +1,45 @@ +import { consume as consumeWS } from '../../../helpers/whitespace'; +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; + +import tokenizeCondition from '.'; + +export default async (state: ITokenizeState) : Promise => { + const { options, stack, tokens } = state; + let { cursor } = state; + + cursor = consumeWS(tokens, cursor); + + if (cursor + 1 >= tokens.length || tokens[cursor].value !== '[') { + return false; + } + cursor += 1; + + const mockState : ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + }; + + if (!await tokenizeCondition(mockState)) { + throw new Error('TODO - SyntaxError: conditional expected'); + } + + cursor = consumeWS(tokens, mockState.cursor); + if ( + cursor >= tokens.length + ) { + throw new Error('TODO - SyntaxError: Unexpected end'); + } + + if (tokens[cursor].value !== ']') { + throw new Error('TODO - SyntaxError: expected \']\''); + } + + state.tokens = mockState.tokens; + state.cursor = cursor + 1; + state.output = mockState.output; + return true; +} \ No newline at end of file diff --git a/src/parse/condition/tokenize/comparison.ts b/src/parse/condition/tokenize/comparison.ts new file mode 100644 index 0000000..9827368 --- /dev/null +++ b/src/parse/condition/tokenize/comparison.ts @@ -0,0 +1,132 @@ +import { consume as consumeWS } from '../../../helpers/whitespace'; + +import type ITokenizeState from '../../../types/tokenize-state'; + +import { + ArgumentsQuantifier, + type IOperator, + comparisonOperators, + OperatorToken, +} from '../operators' + +import Token from '../../token'; + +import tokenizeOperand, { type IOperandState } from './operand'; + +import tokenizeOperator, { type IOperatorState } from './operator'; + +export default async (state: ITokenizeState, asArgument = true) : Promise => { + const { options, stack } = state; + let { tokens, cursor } = state; + + cursor = consumeWS(tokens, cursor); + + if ( + cursor >= tokens.length || + tokens[cursor].value === ']' || + (asArgument && tokens[cursor].value === ',') || + tokens[cursor].value === '&&' || + tokens[cursor].value === '||' + ) { + return false; + } + + const startPosition = tokens[cursor].position; + + const mockState : ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + }; + + let operator : void | IOperator = undefined; + + const leftCheck = await tokenizeOperand( + mockState, + asArgument, + async (state: IOperandState, asArgument: boolean) : Promise => { + const { options, stack, operand, tokens, cursor } = state; + + const mockState : IOperatorState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + }; + + if ( + !operand.tokens.length || + !operand.leadingWhitespace || + !(await tokenizeOperator(mockState, asArgument)) + ) { + return false; + } + + operator = mockState.output; + state.cursor = mockState.cursor; + state.tokens = mockState.tokens; + state.endOfOperand = true; + + return true; + } + ); + + if (!leftCheck) { + throw new Error('TODO - SyntaxError: Left hand expression expected'); + } + const left = mockState.output; + + tokens = mockState.tokens; + cursor = mockState.cursor; + + if (operator == null) { + operator = comparisonOperators.get('exists'); + cursor = consumeWS(tokens, cursor); + } + + let right : undefined | Token; + + const argQuant = (operator).quantifier; + if (argQuant !== ArgumentsQuantifier.LEFTONLY) { + const mockState : ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + } + + if (await tokenizeOperand(mockState, asArgument)) { + tokens = mockState.tokens; + cursor = consumeWS(tokens, mockState.cursor); + right = mockState.output; + + } else if (argQuant === ArgumentsQuantifier.RIGHTREQUIRED) { + throw new Error('TODO - SyntaxError: Right hand expression expected'); + } + } + const args : Token[] = [left]; + if (right) { + args.push(right); + } + + if ( + cursor >= tokens.length || + tokens[cursor].value === ']' || + (asArgument && tokens[cursor].value === ',') + ) { + state.cursor = cursor; + state.tokens = tokens; + state.output = new OperatorToken({ + position: startPosition, + value: (operator).name, + quantifier: (operator).quantifier, + arguments: args, + handle: (operator).handle + }); + return true; + } + + // TODO - custom error - Illegal character + throw new Error('TODO - SyntaxError: illegal character'); +} \ No newline at end of file diff --git a/src/parse/condition/tokenize/index.ts b/src/parse/condition/tokenize/index.ts new file mode 100644 index 0000000..af31912 --- /dev/null +++ b/src/parse/condition/tokenize/index.ts @@ -0,0 +1,52 @@ +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; + +import tokenizeLogicalNot from './logical-not'; +import tokenizeBlock from './block'; +import tokenizeComparison from './comparison'; +import tokenizeLogicalOperator from './logical-operator'; + +export default async (state: ITokenizeState, asArgument = false) : Promise => { + + const { options, stack, tokens, cursor } = state; + + let mockState: ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + }; + + if ( + await tokenizeLogicalNot(mockState) || + await tokenizeBlock(mockState) || + await tokenizeComparison(mockState, asArgument) + ) { + let condition = mockState.output; + + mockState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...(mockState.tokens) ], + cursor: mockState.cursor + }; + while (await tokenizeLogicalOperator(mockState, condition, asArgument)) { + condition = mockState.output; + mockState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...(mockState.tokens) ], + cursor: mockState.cursor + }; + } + + state.tokens = mockState.tokens; + state.cursor = mockState.cursor; + state.output = condition; + + return true; + } + + return false +} \ No newline at end of file diff --git a/src/parse/condition/tokenize/logical-not.ts b/src/parse/condition/tokenize/logical-not.ts new file mode 100644 index 0000000..653e281 --- /dev/null +++ b/src/parse/condition/tokenize/logical-not.ts @@ -0,0 +1,47 @@ +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; + +import { OperatorToken, notOperator } from '../operators'; + +import tokenizeBlock from './block'; + +export default async (state: ITokenizeState) : Promise => { + + const { options, stack, tokens } = state; + let { cursor } = state; + + const startPosition = cursor; + + if ( + cursor + 1 >= tokens.length || + tokens[cursor].value !== '!' || + tokens[cursor + 1].value !== '[' + ) { + return false; + } + + cursor += 1; + + const mockState : ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + }; + + if (await tokenizeBlock(mockState)) { + state.tokens = mockState.tokens; + state.cursor = mockState.cursor; + state.output = new OperatorToken({ + position: startPosition, + value: notOperator.name, + quantifier: notOperator.quantifier, + arguments: [mockState.output], + handle: notOperator.handle + }); + return true; + } + + return false; +}; \ No newline at end of file diff --git a/src/parse/condition/tokenize/logical-operator.ts b/src/parse/condition/tokenize/logical-operator.ts new file mode 100644 index 0000000..82f5766 --- /dev/null +++ b/src/parse/condition/tokenize/logical-operator.ts @@ -0,0 +1,59 @@ +import { consume as consumeWS } from '../../../helpers/whitespace'; + +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; +import { OperatorToken, logicalOperators, type IOperator } from '../operators'; + +import tokenizeLogicalNot from './logical-not'; +import tokenizeBlock from './block'; +import tokenizeComparison from './comparison'; + +export default async (state: ITokenizeState, leftCondition: Token, asArgument = false) : Promise => { + + const { options, stack } = state; + let { tokens, cursor } = state; + + cursor = consumeWS(tokens, cursor); + + const startPosition = tokens[cursor].position; + + if (!logicalOperators.has(tokens[cursor].value)) { + return false; + } + const operator = logicalOperators.get(tokens[cursor].value); + + cursor = consumeWS(tokens, cursor + 1); + + const mockState : ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + }; + + let rightCondition: Token; + if ( + await tokenizeLogicalNot(mockState) || + await tokenizeBlock(mockState) || + await tokenizeComparison(mockState, asArgument) + ) { + tokens = mockState.tokens; + cursor = mockState.cursor; + rightCondition = mockState.output; + + } else { + throw new Error('TODO - SyntaxError: invalid right handle conditional'); + } + + state.tokens = tokens; + state.cursor = cursor; + state.output = new OperatorToken({ + position: startPosition, + value: operator.name, + arguments: [leftCondition, rightCondition], + quantifier: operator.quantifier, + handle: operator.handle + }); + return true; +} \ No newline at end of file diff --git a/src/parse/condition/tokenize/operand.ts b/src/parse/condition/tokenize/operand.ts new file mode 100644 index 0000000..8265f6e --- /dev/null +++ b/src/parse/condition/tokenize/operand.ts @@ -0,0 +1,166 @@ +import TokenType from '../../../types/token-types'; +import type ITokenizeState from '../../../types/tokenize-state'; + +import { consume as consumeWS, is as isWS } from '../../../helpers/whitespace'; + +import { + TextToken, + tokenizeEscape, + tokenizeEscapeBlock, + tokenizeQuoted, + tokenizeSpecial, +} from '../../text'; + +import { tokenizeIf } from '../../if'; +import { tokenizeFunction } from '../../function'; + +import type Token from '../../token'; +import ListToken from '../../list'; + +export interface IOperandState extends ITokenizeState { + endOfOperand?: boolean; + operand: { + tokens: Token[]; + leadingWhitespace: boolean; + }; +} + +type EndCheck = (state: IOperandState, asArgument: boolean) => Promise; + +export default async ( + state: ITokenizeState, + asArgument: boolean, + endCheck?: EndCheck +) : Promise => { + + const { options, stack } = state; + let { tokens, cursor } = state; + + cursor = consumeWS(tokens, cursor); + + const startPosition = cursor; + const operand : Token[] = []; + + let ws = '', wspos = 0; + + while ( + cursor < tokens.length && + tokens[cursor].value !== ']' && + tokens[cursor].value !== '&&' && + tokens[cursor].value !== '||' && + (!(asArgument && tokens[cursor].value === ',')) + ) { + + // consume whitespace + if (isWS(tokens, cursor)) { + if (ws === '') { + wspos = tokens[cursor].position; + } + ws += tokens[cursor].value; + cursor += 1; + continue; + } + + // non literal-text token + const mockState : ITokenizeState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + cursor + } + if ( + await tokenizeEscape(mockState, ['"', '$', '\\', ',', ']',]) || + await tokenizeEscapeBlock(mockState) || + await tokenizeQuoted(mockState) || + await tokenizeSpecial(mockState) || + await tokenizeIf(mockState) || + await tokenizeFunction(mockState) + ) { + const last = operand[operand.length - 1]; + const token = mockState.output; + + if (!last) { + operand.push(mockState.output); + + } else if (last.type === TokenType.TEXT) { + last.value += ws; + if (token.type === TokenType.TEXT) { + last.value += token.value; + } else { + operand.push(token); + } + + } else if (token.type === TokenType.TEXT) { + token.position = wspos; + token.value = ws + token.value; + operand.push(token); + + } else { + operand.push(new TextToken({ + position: wspos, + value: ws + })); + operand.push(token); + } + + ws = ''; + wspos = 0; + + tokens = mockState.tokens; + cursor = mockState.cursor; + + continue; + } + + if (endCheck) { + const checkState : IOperandState = { + options: { ...options }, + stack: [ ...stack ], + tokens: [ ...tokens ], + operand: { + tokens: operand, + leadingWhitespace: ws !== '' + }, + cursor + }; + if (await endCheck(checkState, asArgument)) { + tokens = checkState.tokens; + cursor = checkState.cursor; + if (checkState.endOfOperand) { + break; + } + } + } + + // plain text token + if (!operand.length) { + operand.push(new TextToken(tokens[cursor])); + + } else if (operand[operand.length - 1].type === TokenType.TEXT) { + operand[operand.length - 1].value += ws + tokens[cursor].value; + + } else { + operand.push(new TextToken({ + position: ws !== '' ? wspos : tokens[cursor].position, + value: tokens[cursor].value + })); + } + + ws = ''; + wspos = 0; + cursor += 1; + } + + if (!operand.length) { + return false; + } + + state.tokens = tokens; + state.cursor = cursor; + state.output = new ListToken({ + position: startPosition, + value: operand + }); + + return true; +} \ No newline at end of file diff --git a/src/parse/condition/tokenize/operator.ts b/src/parse/condition/tokenize/operator.ts new file mode 100644 index 0000000..e05859b --- /dev/null +++ b/src/parse/condition/tokenize/operator.ts @@ -0,0 +1,65 @@ +import type ITokenizeState from '../../../types/tokenize-state'; + +import { consume as consumeWS, is as isWS } from '../../../helpers/whitespace'; + +import { comparisonOperators, type IOperator } from '../operators'; + +export interface IOperatorState extends Omit { + output?: IOperator +} + +export default async (state: IOperatorState, asArgument = true) : Promise => { + + const { tokens } = state; + let { cursor } = state; + + if (cursor >= tokens.length) { + return false; + } + + let compname = ''; + + if (tokens[cursor].value === '!') { + compname += '!' + cursor += 1; + if (cursor >= tokens.length) { + return false; + } + } + + if (/^[a-z]+$/i.test(tokens[cursor].value)) { + compname += tokens[cursor].value; + cursor += 1; + + } else { + while ( + cursor < tokens.length && + ( + tokens[cursor].value === '=' || + tokens[cursor].value === '<' || + tokens[cursor].value === '>' + ) + ) { + compname + tokens[cursor].value; + cursor += 1; + } + } + + if ( + compname !== '' && + comparisonOperators.has(compname) && + ( + cursor >= tokens.length || + tokens[cursor].value === ']' || + (asArgument && tokens[cursor].value === ',') || + isWS(tokens, cursor) + ) + ) { + + state.cursor = consumeWS(tokens, cursor); + state.output = comparisonOperators.get(compname); + return true; + } + + return false; +}; \ No newline at end of file diff --git a/src/parse/expression.ts b/src/parse/expression.ts new file mode 100644 index 0000000..249d0b7 --- /dev/null +++ b/src/parse/expression.ts @@ -0,0 +1,62 @@ +import type IParseOptions from '../types/options'; +import type Token from './token'; + +export interface IExpression { + options: IParseOptions, + input: string, + tokens: Token[]; +} + +export default class Expression { + public options: IParseOptions; + public input : string; + public tokens: Token[]; + + constructor(expression: IExpression) { + this.options = expression.options; + this.input = expression.input; + this.tokens = expression.tokens; + } + + toJSON() : Record { + return { + options: { ...(this.options) }, + input: this.input, + value: this.tokens.forEach(value => value.toJSON()) + }; + } + + async evaluate(options: IParseOptions = {}, meta: unknown = {}) : Promise { + const config = { + ...(this.options), + ...options + }; + + let result = ''; + let index = 0; + while (index < this.tokens.length) { + let value = await this.tokens[index].evaluate(config, meta); + index += 1; + + if ( + options.verifyOnly || + value == null || + (typeof value === 'number' && !Number.isFinite(value)) + ) { + continue; + } + + if (typeof value !== 'string') { + value = JSON.stringify(value); + } + + result += value; + } + + if (config.verifyOnly) { + return ''; + } + + return result; + } +} \ No newline at end of file diff --git a/src/parse/function/index.ts b/src/parse/function/index.ts new file mode 100644 index 0000000..f0c9abb --- /dev/null +++ b/src/parse/function/index.ts @@ -0,0 +1,2 @@ +export { default as tokenizeFunction } from './tokenize'; +export { default as FunctionToken } from './token'; \ No newline at end of file diff --git a/src/parse/function/token/index.spec.ts b/src/parse/function/token/index.spec.ts new file mode 100644 index 0000000..e2a1949 --- /dev/null +++ b/src/parse/function/token/index.spec.ts @@ -0,0 +1,220 @@ +import '../../../../jest/helpers'; + +import TokenType from '../../../types/token-types'; + +import FunctionToken from './index'; +import Token from '../../token'; +import { TextToken } from '../../text/'; +import { type IFunctionHandler, type IFunctionLookup } from '../../../types/options'; + +const base = { + prefix: '$', + value: 'test', + arguments: [ + new TextToken({value: 'a'}), + new TextToken({value: 'b'}) + ] +}; + +describe('Default Export', () => { + test('Is a constructor', () => { + expect(typeof FunctionToken).toBe('function'); + expect(FunctionToken).toBeInstanceOf(Function); + expect(FunctionToken.prototype).toBeDefined(); + }); + + test('Has .toJSON() function', () => { + expect(FunctionToken.prototype).toHaveOwnProperty('toJSON'); + expect(typeof FunctionToken.prototype.toJSON).toBe('function'); + }); + + test('Has .evaluate() function', () => { + expect(FunctionToken.prototype).toHaveOwnProperty('evaluate'); + expect(typeof FunctionToken.prototype.evaluate).toBe('function'); + }); +}); + +describe('Constructor', () => { + + test('Errors when token is nullish', () => { + expect(() => { + // @ts-expect-error: Testing nullish token + new FunctionToken(); + }).toThrow(); + }); + + test('Errors when token is not an object', () => { + expect(() => { + // @ts-expect-error: Testing input is not an object + new FunctionToken(true); + }).toThrow(); + }); + + test('Errors when token.prefix is not a string', () => { + expect(() => { + // @ts-expect-error: Testing nullish token.prefix + new FunctionToken({}); + }).toThrow(); + + expect(() => { + // @ts-expect-error: Testing token.prefix is not a string + new FunctionToken({prefix: true}); + }).toThrow(); + }); + + test('Errors when token.value is not a string', () => { + expect(() => { + // @ts-expect-error: Testing nullish token.value + new FunctionToken({prefix: '$'}); + }).toThrow(); + + expect(() => { + // @ts-expect-error: Testing token.value is not string + new FunctionToken({prefix: '$', value: true}); + }).toThrow(); + }); + + test('Errors when token.arguments is not a populated array', () => { + expect(() => { + // @ts-expect-error: Testing unspecified arguments input + new FunctionToken({prefix: '$', value: ''}); + }).toThrow(); + + expect(() => { + // @ts-expect-error: Testing non array arguments input + new FunctionToken({prefix: '$', value: '', arguments: true}); + }).toThrow(); + + expect(() => { + // @ts-expect-error: Testing empty arguments array + new FunctionToken({prefix: '$', value: '', arguments: []}); + }).toThrow(); + }); + + test('Errors when token.arguments contains non-token instance', () => { + expect(() => { + // @ts-expect-error: Testing empty arguments array + new FunctionToken({prefix: '$', value: '', arguments: ['']}); + }).toThrow(); + }); + + test('Errors when neither handler or lookupFn are defined', () => { + expect(() => { + // @ts-expect-error: Testing neither handler or lookupFn specified + new FunctionToken({...base}); + }).toThrow(); + }); + + test('Errors when handler is not an object', () => { + expect(() => { + // @ts-expect-error: Testing handler is not an object + new FunctionToken({...base, handler: true}); + }).toThrow(); + }); + + test('Errors when handler.evaluator is nullish', () => { + expect(() => { + // @ts-expect-error: Testing handler.evaluator is not specified + new FunctionToken({...base, handler: { }}); + }).toThrow(); + }); + + test('Errors when handler.evaluator is not a function', () => { + expect(() => { + // @ts-expect-error: Testing evaluator is not a function + new FunctionToken({...base, handler: { evaluator: ''}}); + }).toThrow(); + }); + + test('Errors when specified handler.stackCheck is not a function', () => { + expect(() => { + // @ts-expect-error: Testing stackCheck is not a function + new FunctionToken({...base, handler: { stackCheck: '' }}); + }).toThrow(); + }); + + test('Errors when specified handler.argsCheck is not a function', () => { + expect(() => { + // @ts-expect-error: Testing argsCheck is not a function + new FunctionToken({...base, handler: { argsCheck: '' }}); + }).toThrow(); + }); + + test('Errors when specified lookupFn is not a function', () => { + expect(() => { + // @ts-expect-error: Testing specified lookupFn is not a function + new FunctionToken({...base, lookupFn: true}); + }).toThrow(); + }); + + test('Constructs without error when input is valid', () => { + expect(() => { + new FunctionToken({...base, handler: { evaluate: async () => undefined } }); + }).not.toThrow(); + }); +}); + +describe('Instance', () => { + const handler : IFunctionHandler = { evaluate: async () => undefined }; + const token = new FunctionToken({...base, handler }); + + test('Is instance of ListToken and Token', () => { + expect(token).toBeInstanceOf(FunctionToken); + expect(token).toBeInstanceOf(Token); + }); + + test('Sets .type to TokenType.FUNCTION', () => { + expect(token.type).toBe(TokenType.FUNCTION); + }); + + test('Stores function identifier(.value)', () => { + expect(token.value).toBe('test'); + }); + + test('Stores prefix', () => { + expect(token.prefix).toBe('$'); + }); + + test('Stores arguments', () => { + expect(token.arguments === base.arguments).toBe(true); + }); + + test('Stores handler', () => { + expect(token.handler === handler).toBe(true); + }); + + test('Stores lookupFn', () => { + const handler : IFunctionHandler = { evaluate: async () => undefined }; + const lookupFn : IFunctionLookup = async () => handler; + const token = new FunctionToken({ ...base, lookupFn }); + expect(token.lookupFn === lookupFn).toBe(true); + }); +}); + +describe('Instance#toJSON() ', () => { + const handler : IFunctionHandler = { evaluate: async () => undefined }; + let token : FunctionToken; + beforeEach(() => { + token = new FunctionToken({...base, handler }); + }); + + test('calls super.toJSON()', () => { + const spy = jest.spyOn(Token.prototype, 'toJSON'); + token.arguments = []; + + expect(() => token.toJSON()).not.toThrow(); + expect(spy).toHaveBeenCalledTimes(1); + jest.clearAllMocks(); + }); + + test('Returns prefix', () => { + const result = token.toJSON(); + expect(result).toHaveOwnProperty('prefix', '$'); + }); + + test('Returns arguments', () => { + const result = token.toJSON(); + expect(result).toHaveOwnProperty('arguments'); + expect(result.arguments).toHaveLength(2); + }); +}); \ No newline at end of file diff --git a/src/parse/function/token/index.ts b/src/parse/function/token/index.ts new file mode 100644 index 0000000..abff01f --- /dev/null +++ b/src/parse/function/token/index.ts @@ -0,0 +1,176 @@ +import TokenType from '../../../types/token-types'; +import { type default as IParserOptions, type IFunctionLookup, type IFunctionHandler } from '../../../types/options'; +import Token, { type IToken } from '../../token'; + +interface IFunctionBaseToken extends IToken { + prefix: string; + value: string; + arguments: Token[]; +} + +export interface IFunctionHandlerToken extends IFunctionBaseToken { + handler: IFunctionHandler; + lookupFn?: never; +} + +interface IFunctionLookupToken extends IFunctionBaseToken { + handler?: never; + lookupFn: IFunctionLookup; +} + +export type IFunctionToken = IFunctionHandlerToken | IFunctionLookupToken; + +export default class FunctionToken extends Token { + public prefix: string; + public value: string; + public arguments: Token[]; + public handler: IFunctionHandler; + public lookupFn: IFunctionLookup; + + constructor(token: IFunctionToken) { + + if (token == null) { + throw new Error('TODO - ExpressionError: token info missing') + } + if (typeof token !== 'object') { + throw new Error('TODO - ExpressionError: token must be an object'); + } + if (typeof token.prefix !== 'string') { + throw new Error('TODO - ExpressionError: token contains invalid prefix'); + } + + if (typeof token.value !== 'string') { + throw new Error('TODO - ExpressionError: token.value must be a string'); + } + + if (!Array.isArray(token.arguments)) { + throw new Error('TODO - ExpressionError: token info contains invalid arguments') + } + + if (!token.arguments.length) { + throw new Error('TODO - ExpressionError: token info arguments is unpopulated array') + } + + if (token.arguments.some((value: unknown) => !(value instanceof Token))) { + throw new Error('arguments must be a list of tokens'); + } + + if (token.handler == null && token.lookupFn == null) { + throw new Error('TODO - ExpressionError: token info not contain lookupFn or handlerFn'); + + } else if (token.handler != null) { + if (token.lookupFn != null) { + throw new Error('TODO - ExpressionError: token contains both lookupFn and handlerFn'); + } + + const handler : IFunctionHandler = token.handler; + if (typeof handler !== 'object') { + throw new Error('TODO - ExpressionError: specified handler must be an object'); + } + if (handler.evaluate == null) { + throw new Error('TODO - ExpressionError: specified handler does not have .evaluator property'); + } + if (typeof handler.evaluate !== 'function') { + throw new Error('TODO - ExpressionError: specified handler.evaluator property not a function'); + } + if (handler.stackCheck != null && typeof handler.stackCheck !== 'function') { + throw new Error('TODO - ExpressionError: stackCheck must be a function'); + } + if (handler.argsCheck != null && typeof handler.argsCheck !== 'function') { + throw new Error('TODO - ExpressionError: argsCheck must be a function'); + } + + } else if (typeof token.lookupFn !== 'function') { + throw new Error('TODO - ExpressionError: specified lookupFn must be a function'); + } + + super({ + type: TokenType.FUNCTION, + ...token + }); + this.prefix = '' + token.prefix; + this.arguments = token.arguments; + + if (token.handler != null) { + this.handler = token.handler; + + } else { + this.lookupFn = token.lookupFn; + } + } + + toJSON() : Record { + return { + ...(super.toJSON()), + prefix: this.prefix, + arguments: this.arguments.map(value => value.toJSON()) + } + } + + async evaluate(options: IParserOptions, meta: unknown) : Promise { + if (options == null) { + options = {}; + } + if (meta == null) { + meta = {}; + } + if (options.stack == null) { + options.stack = []; + } + const stack = [ ...options.stack ] + + let handler : IFunctionHandler; + if (this.handler) { + handler = this.handler; + + } else { + handler = await this.lookupFn(this.value); + } + + if (handler == null) { + throw new Error(`TODO - ExpressionError: No handler for ${this.prefix}${this.value}`); + } + + if (!options.skipStackCheck && handler.stackCheck != null) { + try { + await handler.stackCheck.call(this, options, meta, stack); + } catch (err) { + throw new Error('TODO - ExpressionError: stack check failed') + } + } + + let args : unknown[] = []; + if (!options.verifyOnly && handler.defer === true) { + args = this.arguments; + + } else if (this.arguments != null) { + const argList = this.arguments; + for (let idx = 0; idx < argList.length; idx += 1) { + const opts = { + ...options, + stack: [...(options.stack), `${this.prefix}${this.value}`] + } + const arg = await argList[idx].evaluate(opts, meta); + args.push(arg); + } + } + + if (options.verifyOnly) { + return; + } + + if ( + !options.skipArgumentsCheck && + handler.defer !== true && + handler.argsCheck != null + ) { + try { + await handler.argsCheck.call(this, options, meta, args); + } catch (err) { + throw new Error(`TODO - ArgumentsError: ${err.message}`); + } + } + + return handler.evaluate.call(this, options, meta, ...args); + } +} \ No newline at end of file diff --git a/src/parse/function/tokenize/index.ts b/src/parse/function/tokenize/index.ts new file mode 100644 index 0000000..4f4ab93 --- /dev/null +++ b/src/parse/function/tokenize/index.ts @@ -0,0 +1,66 @@ +import has from '../../../helpers/has'; + +import { type IFunctionLookup, type IFunctionHandler } from '../../../types/options'; + +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; +import FunctionalToken from '../token'; + +import { tokenizeArgumentsList } from '../../argument-list'; + +export default async (state: ITokenizeState) : Promise => { + const { tokens, stack, options } = state; + let cursor = state.cursor; + + if (tokens[cursor]?.value !== '$' || tokens[cursor + 1] == null) { + return false; + } + const position = tokens[cursor].position; + + cursor += 1; + + let prefix = '$', + varname : string = tokens[cursor].value.toLowerCase(), + lookupFn : IFunctionLookup; + + cursor += 1; + + if (has(options.functionHandlers, varname)) { + const handler : IFunctionHandler = (>options.functionHandlers)[varname]; + lookupFn = async () => handler; + + } else if ( + cursor >= tokens.length && + has(options.functionLookups, varname) + ) { + lookupFn = (>options.functionLookups)[varname] + prefix += varname; + varname = tokens[cursor].value.toLowerCase(); + cursor += 1; + + } else { + return false; + } + + const mockState : ITokenizeState = { + options: { ...options }, + tokens, + cursor, + stack: [ ...stack, `${prefix}${varname}`] + } + + await tokenizeArgumentsList(mockState); + + state.tokens = mockState.tokens; + state.output = new FunctionalToken({ + position, + prefix, + value: varname, + arguments: (mockState.output || []), + lookupFn + }); + state.cursor = mockState.cursor; + + return true; +}; \ No newline at end of file diff --git a/src/parse/if/index.ts b/src/parse/if/index.ts new file mode 100644 index 0000000..0520a30 --- /dev/null +++ b/src/parse/if/index.ts @@ -0,0 +1,2 @@ +export { default as tokenizeIf } from './tokenize'; +export { default as IfToken } from './token'; \ No newline at end of file diff --git a/src/parse/if/token/index.spec.ts b/src/parse/if/token/index.spec.ts new file mode 100644 index 0000000..8dda246 --- /dev/null +++ b/src/parse/if/token/index.spec.ts @@ -0,0 +1,305 @@ +import '../../../../jest/helpers'; + +import IfToken from './index'; +import { ArgumentsQuantifier, OperatorToken } from '../../condition/'; +import Token from '../../token'; +import { TextToken } from '../../text'; + +test('Exports constructor', () => { + expect(typeof IfToken).toBe('function'); + expect(IfToken.prototype).toBeDefined(); +}); + +test('Has .toJSON() function', () => { + expect(IfToken.prototype).toHaveOwnProperty('toJSON'); + expect(typeof IfToken.prototype.toJSON).toBe('function'); +}); + +test('Has .evaluate function', () => { + expect(IfToken.prototype).toHaveOwnProperty('evaluate'); + expect(typeof IfToken.prototype.evaluate).toBe('function'); +}); + +test('Constructor throws when token is nullish', () => { + expect(() => { + // @ts-expect-error: Testing unspecified input + new IfToken() + }).toThrow(); + + expect(() => { + const input : void | null = undefined; + // @ts-expect-error: Testing undefined input + new IfToken(input); + }).toThrow(); + + expect(() => { + const input : void | null = null; + // @ts-expect-error: Testing null input + new IfToken(input); + }).toThrow(); +}); + +test('Consturctot throw when token is not an object', () => { + expect(() => { + // @ts-expect-error: Testing invalid token input + new IfToken('test') + }).toThrow(); +}); + +test('Constructor throws when condition is nullish', () => { + expect(() => { + // @ts-expect-error: Testing nullish condition input + new IfToken({}); + }).toThrow(); + + expect(() => { + // @ts-expect-error: Testing nullish condition input + new IfToken({condition: undefined}); + }).toThrow(); + + expect(() => { + // @ts-expect-error: Testing nullish condition input + new IfToken({condition: null}); + }).toThrow(); +}); + +test('Constructor throws when condition is not an OperatorToken instance', () => { + expect(() => { + // @ts-expect-error: Testing nullish condition input + new IfToken({condition: 'text'}); + }).toThrow(); +}); + +test('Constructor throws if whenTrue is nullish', () => { + const op = new OperatorToken({ + quantifier: ArgumentsQuantifier.LEFTONLY, + arguments: [new Token()], + handle: async () => false + }); + + expect(() => { + /*eslint-disable-next-line @typescript-eslint/ban-ts-comment*/ + // @ts-ignore: Testing whenTrue value is not specified + new IfToken({condition: op}); + }).toThrow(); + + expect(() => { + /*eslint-disable-next-line @typescript-eslint/ban-ts-comment*/ + // @ts-ignore: Testing whenTrue value is undefined + new IfToken({ condition: op, whenTrue: undefined }); + }).toThrow(); + + expect(() => { + /*eslint-disable-next-line @typescript-eslint/ban-ts-comment*/ + // @ts-ignore: Testing whenTrue value null + new IfToken({ condition: op, whenTrue: null }); + }).toThrow(); +}); + +test('Constructor throws if whenTrue is not a token', () => { + const op = new OperatorToken({ + quantifier: ArgumentsQuantifier.LEFTONLY, + arguments: [new Token()], + handle: async () => false + }); + + expect(() => { + const input = { condition: op, whenTrue: '' }; + // @ts-expect-error: Testing whenTrue value is not a Token + new IfToken(input); + }).toThrow(); +}); + +test('Constructor throws if whenFalse is specified but not a token', () => { + const op = new OperatorToken({ + quantifier: ArgumentsQuantifier.LEFTONLY, + arguments: [new Token()], + handle: async () => false + }); + + expect(() => { + // @ts-expect-error: Testing whenTrue value is not a Token + new IfToken({ condition: op, whenTrue: new Token(), whenFalse: '' }); + }).toThrow(); +}); + +test('Constructs without error', () => { + const op = new OperatorToken({ + quantifier: ArgumentsQuantifier.LEFTONLY, + arguments: [new Token()], + handle: async () => false + }); + expect(() => { + new IfToken({ + condition: op, + whenTrue: new Token() + }); + }).not.toThrow(); +}); + +test('.toJSON() calls super.toJSON', () => { + const spy = jest.spyOn(Token.prototype, 'toJSON'); + const token = new IfToken({ + condition: new OperatorToken({ + quantifier: ArgumentsQuantifier.LEFTONLY, + arguments: [new Token()], + handle: async () => false + }), + whenTrue: new Token() + }); + expect(() => token.toJSON()).not.toThrow(); + expect(spy).toHaveBeenCalled(); + jest.clearAllMocks(); +}); + +test('.toJSON() returns proper representation', () => { + expect.assertions(8); + + const toJSONResult = {}; + + let condToJSONCalls = 0; + const condition = new OperatorToken({ + quantifier: ArgumentsQuantifier.LEFTONLY, + arguments: [new Token()], + handle: async () => false + }); + condition.toJSON = () : Record => { + condToJSONCalls += 1; + return toJSONResult; + }; + + let whenTrueJSONCalls = 0; + const whenTrue = new Token(); + whenTrue.toJSON = () : Record => { + whenTrueJSONCalls += 1; + return toJSONResult; + }; + + let whenFalseJSONCalls = 0; + const whenFalse = new Token(); + whenFalse.toJSON = () : Record => { + whenFalseJSONCalls += 1; + return toJSONResult; + }; + + const token1 = new IfToken({ + condition, + whenTrue + }); + const result1 = token1.toJSON(); + expect(condToJSONCalls).toBe(1); + expect(result1).toHaveOwnProperty('condition', toJSONResult); + + expect(whenTrueJSONCalls).toBe(1); + expect(result1).toHaveOwnProperty('whenTrue', toJSONResult); + + expect(whenFalseJSONCalls).toBe(0); + expect(result1.whenFalse).toBeUndefined(); + + const token2 = new IfToken({ + condition, + whenTrue, + whenFalse + }); + const result2 = token2.toJSON(); + expect(whenFalseJSONCalls).toBe(1); + expect(result2).toHaveOwnProperty('whenFalse', toJSONResult); +}); + +test('.evaluate() calls evaluate for condition/falls back to defaults for inputs', async () => { + let conditionCalled = 0, + optionsSet = false, + metaSet = false, + whenTrueCalled = 0; + + const condition = new OperatorToken({ + position: 0, + value: 'test', + quantifier: ArgumentsQuantifier.LEFTONLY, + defer: false, + arguments: [new TextToken({value: 'text'})], + handle: async function (options, meta) : Promise { + conditionCalled += 1; + optionsSet = !!options; + metaSet = !!meta; + return true; + } + }); + + const whenTrue = new Token(); + whenTrue.evaluate = async function () { + whenTrueCalled += 1; + return false; + } + + const token = new IfToken({ + condition, + whenTrue: whenTrue + }); + + expect.assertions(4); + + // @ts-expect-error : testing empty inputs + await token.evaluate(); + + expect(conditionCalled).toBe(1); + expect(optionsSet).toBe(true); + expect(metaSet).toBe(true); + expect(whenTrueCalled).toBe(1); +}); + +test('.evaluate() evaluates all inputs when verifyOnly is true', async () => { + const condition = new OperatorToken({ + position: 0, + value: 'test', + quantifier: ArgumentsQuantifier.LEFTONLY, + defer: false, + arguments: [new TextToken({value: 'text'})], + handle: async function () : Promise { + return true; + } + }); + + let whenCalls = 0; + const when = new Token(); + when.evaluate = async function () { + whenCalls += 1; + return true; + } + + const token = new IfToken({ condition, whenTrue: when, whenFalse: when }); + + expect.assertions(2); + const result = await token.evaluate({verifyOnly: true}, {}); + + expect(result).toBeUndefined(); + expect(whenCalls).toBe(2); +}); + +test('.evaluate() evaluates false argument when condition is false and returns result', async () => { + const condition = new OperatorToken({ + position: 0, + value: 'test', + quantifier: ArgumentsQuantifier.LEFTONLY, + defer: false, + arguments: [new TextToken({value: 'text'})], + handle: async function () : Promise { + return false; + } + }); + + let whenCalls = 0; + const when = new Token(); + when.evaluate = async function () { + whenCalls += 1; + return 'falsey'; + } + + const token = new IfToken({ condition, whenTrue: new Token(), whenFalse: when }); + + expect.assertions(2); + const result = await token.evaluate({}, {}); + + expect(result).toBe('falsey') + expect(whenCalls).toBe(1); +}); \ No newline at end of file diff --git a/src/parse/if/token/index.ts b/src/parse/if/token/index.ts new file mode 100644 index 0000000..72da2d5 --- /dev/null +++ b/src/parse/if/token/index.ts @@ -0,0 +1,93 @@ +import TokenType from '../../../types/token-types'; +import type IParserOptions from '../../../types/options'; + +import Token from '../../token'; + +import { OperatorToken } from '../../condition'; + +export interface IIfToken { + position?: number; + condition: OperatorToken; + whenTrue: Token, + whenFalse?: Token +} + +export default class IfToken extends Token { + public condition: OperatorToken; + public whenTrue: Token; + public whenFalse?: Token; + + constructor(token: IIfToken) { + if (token == null) { + throw new Error('TODO - ExpressionError: token not specified'); + } + if (typeof token !== 'object') { + throw new Error('TODO - ExpressionError: token must be an object'); + } + if (token.condition == null) { + throw new Error('TODO - ExpressionError: condition not specified'); + } + if (!(token.condition instanceof OperatorToken)) { + throw new Error('TODO - ExpressionError: condition must be an instance of OperatorToken'); + } + if (token.whenTrue == null) { + throw new Error('TODO - ExpressionError: truthy argument must be specified'); + } + if (!(token.whenTrue instanceof Token)) { + throw new Error('TODO - ExpressionError: truthy argument must be a token instance'); + } + if (token.whenFalse != null && !(token.whenFalse instanceof Token)) { + throw new Error('TODO - ExpressionError: falsy argument must be a token instance'); + } + + super({ + ...token, + type: TokenType.IFSTATEMENT, + value: 'if' + }); + this.condition = token.condition; + this.whenTrue = token.whenTrue; + this.whenFalse = token.whenFalse; + } + + toJSON() : Record { + const result : Record = { + ...(super.toJSON()), + condition: this.condition.toJSON(), + whenTrue: this.whenTrue.toJSON() + }; + if (this.whenFalse != null) { + result.whenFalse = (this.whenFalse).toJSON(); + } + return result; + } + + async evaluate(options: IParserOptions, meta: unknown) : Promise { + if (options == null) { + options = {}; + } + + if (meta == null) { + meta = {}; + } + + const res = await this.condition.evaluate(options, meta); + + if (options.verifyOnly) { + await this.whenTrue.evaluate(options, meta); + + if (this.whenFalse != null) { + await this.whenFalse.evaluate(options, meta); + } + return; + } + + if (res != null && res !== false) { + return this.whenTrue.evaluate(options, meta); + } + + if (this.whenFalse != null) { + return this.whenFalse.evaluate(options, meta); + } + } +} \ No newline at end of file diff --git a/src/parse/if/tokenize/index.ts b/src/parse/if/tokenize/index.ts new file mode 100644 index 0000000..4ce2542 --- /dev/null +++ b/src/parse/if/tokenize/index.ts @@ -0,0 +1,69 @@ +import TokenType from '../../../types/token-types'; +import type ITokenizeState from '../../../types/tokenize-state'; +import { ExpressionSyntaxError } from '../../../errors'; + +import Token from '../../token'; +import IfToken from '../token'; + +import { type OperatorToken } from '../../condition'; + +import { tokenizeArgumentsList } from '../../argument-list'; + +export default async (state: ITokenizeState) : Promise => { + const { tokens, stack, options } = state; + let cursor = state.cursor; + + if ( + tokens[cursor]?.value !== '$' || + tokens[cursor + 1]?.value !== 'if' || + tokens[cursor + 2]?.value !== '[' + ) { + return false; + } + + const position = tokens[cursor].position; + cursor += 2; + + const mockState : ITokenizeState = { + options: { ...options }, + tokens, + cursor, + stack: [...stack, '$if'] + } + await tokenizeArgumentsList(mockState, true); + + const args = mockState.output; + + if (args.length > 3) { + throw new ExpressionSyntaxError('Expected end of arguments', args[3].position); + } + + if (args.length === 3 && args[2].type === TokenType.EMPTY) { + args.pop(); + } + if (args.length === 2 && args[1].type === TokenType.EMPTY) { + args.pop(); + } + + state.tokens = mockState.tokens; + state.cursor = mockState.cursor; + + // $if[] or $if[] or $if[,] or $if[,,] + if (args.length < 2) { + state.output = new Token({ + position: position, + type: TokenType.EMPTY + }); + + // $if[, ] or $if[, ,] or $if[, , ] + } else { + state.output = new IfToken({ + position, + condition: args[0], + whenTrue: args[1], + whenFalse: args[2] + }); + } + + return true; +} \ No newline at end of file diff --git a/src/parse/index.ts b/src/parse/index.ts new file mode 100644 index 0000000..561a9ec --- /dev/null +++ b/src/parse/index.ts @@ -0,0 +1,81 @@ +import type IParseOptions from '../types/options'; +import type ITokenizeState from '../types/tokenize-state'; +import TokenType from '../types/token-types'; +import getPotentialTokens from '../helpers/get-potential-tokens'; + +import type Token from './token'; +import Expression from './expression'; + +import { + TextToken, + tokenizeEscape, + tokenizeEscapeBlock, + tokenizeQuoted, + tokenizeSpecial +} from './text'; + +import { tokenizeIf } from './if' +import { tokenizeFunction } from './function'; + +export default async (options: IParseOptions, subject: string) : Promise => { + if (subject == null || typeof subject !== 'string') { + throw new TypeError('input must be a string'); + } + + let tokens = getPotentialTokens(options, subject); + let cursor = 0; + + const result : Token[] = []; + + while (cursor < tokens.length) { + const mockState : ITokenizeState = { + options: { ...options }, + stack: [], + tokens: [ ...tokens ], + cursor + }; + + if ( + await tokenizeEscape(mockState) || + await tokenizeEscapeBlock(mockState) || + await tokenizeQuoted(mockState) || + await tokenizeSpecial(mockState) || + await tokenizeIf(mockState) || + await tokenizeFunction(mockState) + ) { + const lastToken : Token = result[result.length - 1]; + if ( + lastToken != null && + lastToken.type === TokenType.TEXT && + mockState.output && + (mockState.output).type === TokenType.TEXT + ) { + (lastToken.value) += (mockState.output).value; + + } else { + result.push(mockState.output); + } + + tokens = mockState.tokens; + cursor = mockState.cursor; + continue; + } + + // Assume anything else is plain text + const last : Token = result[result.length - 1]; + if (last != null && last.type === TokenType.TEXT) { + last.value += tokens[cursor].value; + + } else { + result.push(new TextToken(tokens[cursor])); + } + + cursor += 1; + } + + return new Expression({ + options: options, + input: subject, + tokens: result + }); +} \ No newline at end of file diff --git a/src/parse/list/index.spec.ts b/src/parse/list/index.spec.ts new file mode 100644 index 0000000..5b283e3 --- /dev/null +++ b/src/parse/list/index.spec.ts @@ -0,0 +1,199 @@ +import '../../../jest/helpers'; + +import TokenType from '../../types/token-types'; +import IParseOptions from '../../types/options'; + +import Token from '../token'; +import ListToken from './index'; + +test('Exports a constructor', () => { + expect(typeof ListToken).toBe('function'); + expect(ListToken.prototype).toBeDefined(); +}); + +test('Has .toJSON() function', () => { + expect(ListToken.prototype).toHaveOwnProperty('toJSON'); + expect(typeof ListToken.prototype.toJSON).toBe('function'); +}); + +test('Has .evaluate() function', () => { + expect(ListToken.prototype).toHaveOwnProperty('evaluate'); + expect(typeof ListToken.prototype.evaluate).toBe('function'); +}); + +test('Constructor errors when token is nullish', () => { + expect(() => { + // @ts-expect-error: Testing nullish token + new ListToken(); + }).toThrow(); +}); + +test('Constructor errors when token is not an object', () => { + expect(() => { + // @ts-expect-error: Testing invalid token + new ListToken(true); + }).toThrow(); +}); + +test('Constructor errors when token.value is nullish', () => { + expect(() => { + // @ts-expect-error: Testing nullish token.value + new ListToken({}); + }).toThrow(); +}); + +test('Constructor errors when token.value is not an array', () => { + expect(() => { + // @ts-expect-error: Testing invalid token.value + new ListToken({value: ''}); + }).toThrow(); +}); + +test('Constructor errors when token.value contains a non-token instance', () => { + expect(() => { + // @ts-expect-error: Testing invalid token.value + new ListToken({value: ['']}); + }).toThrow(); +}); + +test('Constructs without error', () => { + expect(() => new ListToken({value: []})).not.toThrow(); +}); + +test('Instance to be instance of ListToken and Token', () => { + const token = new ListToken({value: []}); + expect(token).toBeInstanceOf(ListToken); + expect(token).toBeInstanceOf(Token); +}); + +test('.type is set to TokenType.LIST', () => { + const token = new ListToken({value: []}); + expect(token).toHaveOwnProperty('type', TokenType.LIST); +}); + +test('.value is set to input', () => { + const value : Token[] = []; + const token = new ListToken({ value }); + expect(token).toHaveOwnProperty('value', value); +}); + +test('.toJSON() calls super.toJSON()', () => { + const spy = jest.spyOn(Token.prototype, 'toJSON'); + const token = new ListToken({ value: [] }); + expect(() => token.toJSON()).not.toThrow(); + expect(spy).toHaveBeenCalledTimes(1); + jest.clearAllMocks(); +}); + +test('.toJSON() returns valid representation', () => { + const value = new Token(); + let calls = 0; + value.toJSON = function(this: Token) : Record { + calls += 1; + return Token.prototype.toJSON.call(this); + }; + + const token = new ListToken({value: [value]}); + const json = token.toJSON(); + expect(calls).toBe(1); + + expect(json).toHaveOwnProperty('value'); + expect(Array.isArray(json.value)).toBeTruthy(); + expect((json.value).length).toBe(1); +}); + +test('.evaluate() calls evaluate for values/falls back to defaults for inputs', async () => { + const value = new Token(); + + let receivedOptions : void | IParseOptions = undefined; + let receivedMeta : void | unknown = undefined; + value.evaluate = async function(options: IParseOptions, meta: unknown) : Promise { + receivedOptions = options; + receivedMeta = meta; + return; + }; + const token = new ListToken({value: [value]}); + + // @ts-expect-error : Testing nulled inputs + await token.evaluate(); + expect(receivedOptions).toBeDefined(); + expect(receivedMeta).toBeDefined(); +}); + +test('.evaluate() returns undefined when options.verifyOnly is specified', async () => { + const value = new Token(); + value.evaluate = async function() : Promise { + return 'text'; + } + const token = new ListToken({value: [value]}); + + const result = await token.evaluate({verifyOnly: true}, {}); + expect(result).toBeUndefined(); +}); + +test('.evaluate() sets result to value when result is not set', async () => { + const value = new Token(); + value.evaluate = async function() : Promise { + return 'test'; + } + const token = new ListToken({value: [value]}); + + const result = await token.evaluate({}, {}); + expect(result).toBe('test'); +}); + +test('.evaluate() returns null if only a single value is given and its null', async () => { + const value = new Token(); + value.evaluate = async function() : Promise { + return null; + } + const token = new ListToken({value: [value]}); + + const result = await token.evaluate({}, {}); + expect(result).toBeNull(); +}); + +test('.evaluate() does not append non-textable values', async () => { + const value1 = new Token(); + value1.evaluate = async function() : Promise { return 'a'; } + + const value2 = new Token(); + value2.evaluate = async function() : Promise { return; } + + const value3 = new Token(); + value3.evaluate = async function() : Promise { return null; } + + const value4 = new Token(); + value4.evaluate = async function() : Promise { return 'b'; } + + const token = new ListToken({value: [value1, value2, value3, value4]}); + + const result = await token.evaluate({}, {}); + expect(result).toBe('ab'); +}); + +test('.evaluate() converts to text when appending', async () => { + const value1 = new Token(); + value1.evaluate = async function() : Promise { return {}; } + + const value2 = new Token(); + value2.evaluate = async function() : Promise { return 'a'; } + + const token = new ListToken({value: [value1, value2]}); + + const result = await token.evaluate({}, {}); + expect(result).toBe('{}a'); +}); + +test('.evaluate() ignores functions', async () => { + const value1 = new Token(); + value1.evaluate = async function() : Promise { return (()=>1); } + + const value2 = new Token(); + value2.evaluate = async function() : Promise { return 'a'; } + + const token = new ListToken({value: [value1, value2]}); + + const result = await token.evaluate({}, {}); + expect(result).toBe('a'); +}); \ No newline at end of file diff --git a/src/parse/list/index.ts b/src/parse/list/index.ts new file mode 100644 index 0000000..6005e88 --- /dev/null +++ b/src/parse/list/index.ts @@ -0,0 +1,96 @@ +import TokenType from '../../types/token-types'; +import type IParserOptions from '../../types/options'; + +import toText from '../../helpers/to-text'; + +import Token, { type IToken } from '../token'; + +export interface IListToken extends IToken { + value: Token[]; +} + +export default class ListToken extends Token { + public value : Token[]; + + constructor(token: IListToken) { + if (token == null) { + throw new Error('TODO - ExpressionError: token not specified'); + } + if (typeof token !== 'object') { + throw new Error('TODO - ExpressionError: token must be an object'); + } + if (token.value == null) { + throw new Error('TODO - ExpressionError: token list not specified'); + } + if (!Array.isArray(token.value)) { + throw new Error('TODO - ExpressionError: token list must be an array') + } + + for (let idx = 0; idx < token.value.length; idx += 1) { + if (!(token.value[idx] instanceof Token)) { + throw new Error('value list must contain only tokens'); + } + } + + super({ + ...token, + type: TokenType.LIST + }); + } + + toJSON() : Record { + return { + ...(super.toJSON()), + value: this.value.map(value => value.toJSON()) + }; + } + + async evaluate(options: IParserOptions, meta: unknown): Promise { + if (options == null) { + options = {}; + } + if (meta == null) { + meta = {}; + } + + const parts = this.value; + + let res : unknown; + for (let idx = 0; idx < parts.length; idx += 1) { + const value = await parts[idx].evaluate(options, meta); + + if (options.verifyOnly) { + continue; + } + + if (value === undefined) { + continue; + } + + if (res == null) { + res = value; + continue; + } + + const strValue = toText(value); + if (strValue == null) { + continue; + } + + if (typeof res !== 'string') { + const strRes = toText(res); + if (strRes == null) { + res = strValue; + + } else { + res = strRes + strValue; + } + continue; + } + + res += strValue; + } + + return res; + } +} \ No newline at end of file diff --git a/src/parse/text/index.spec.ts b/src/parse/text/index.spec.ts new file mode 100644 index 0000000..19c4bdb --- /dev/null +++ b/src/parse/text/index.spec.ts @@ -0,0 +1,37 @@ +import { + TextToken, + tokenizeEscape, + tokenizeEscapeBlock, + tokenizeQuoted, + tokenizeSpecial +} from './index'; + +test('Exports TextToken constructor', () => { + expect(typeof TextToken).toBe('function'); + expect(TextToken).toBeInstanceOf(Function); + expect(TextToken.prototype).toBeDefined(); +}); + +test('Exports tokenizeEscape function', () => { + expect(typeof tokenizeEscape).toBe('function'); + expect(tokenizeEscape).toBeInstanceOf(Function); + expect(tokenizeEscape.prototype).toBeUndefined(); +}); + +test('Exports tokenizeEscapeBlock function', () => { + expect(typeof tokenizeEscapeBlock).toBe('function'); + expect(tokenizeEscapeBlock).toBeInstanceOf(Function); + expect(tokenizeEscapeBlock.prototype).toBeUndefined(); +}); + +test('Exports tokenizeQuoted function', () => { + expect(typeof tokenizeQuoted).toBe('function'); + expect(tokenizeQuoted).toBeInstanceOf(Function); + expect(tokenizeQuoted.prototype).toBeUndefined(); +}); + +test('Exports tokenizeSpecial function', () => { + expect(typeof tokenizeSpecial).toBe('function'); + expect(tokenizeSpecial).toBeInstanceOf(Function); + expect(tokenizeSpecial.prototype).toBeUndefined(); +}); \ No newline at end of file diff --git a/src/parse/text/index.ts b/src/parse/text/index.ts new file mode 100644 index 0000000..a4cc728 --- /dev/null +++ b/src/parse/text/index.ts @@ -0,0 +1,6 @@ +export { default as TextToken, type ITextToken } from './token'; + +export { default as tokenizeEscape } from './tokenize/escape-single'; +export { default as tokenizeEscapeBlock } from './tokenize/escape-block'; +export { default as tokenizeQuoted } from './tokenize/quoted'; +export { default as tokenizeSpecial } from './tokenize/special'; \ No newline at end of file diff --git a/src/parse/text/token/index.spec.ts b/src/parse/text/token/index.spec.ts new file mode 100644 index 0000000..fd52841 --- /dev/null +++ b/src/parse/text/token/index.spec.ts @@ -0,0 +1,42 @@ +import '../../../../jest/helpers'; + +import Token from '../../token'; +import TextToken from './index'; + +test('Exports a function', () => { + expect(typeof TextToken).toBe('function'); + expect(TextToken.prototype).toBeDefined(); +}); + +test('Throws an error if specified input is not string', () => { + expect(() => new TextToken({ + // @ts-expect-error: Testing non-string values + value: false + })).toThrow(); +}); + +test('Constructs when inputs are valid', () => { + expect(() => new TextToken()).not.toThrow(); +}); + +test('Instances derive from Token', () => { + expect(new TextToken()).toBeInstanceOf(Token); +}); + +test('Defaults value to empty string', () => { + expect(new TextToken()).toHaveOwnProperty('value', ''); +}); + +test('Stores value properly', () => { + expect(new TextToken({value: 'test'})).toHaveOwnProperty('value', 'test'); +}); + +test('Evaluates to value property', async () => { + expect.assertions(2); + + const result = await (new TextToken()).evaluate({}, {}); + expect(result).toBe(''); + + const result2 = await (new TextToken({value: 'test'})).evaluate({}, {}); + expect(result2).toBe('test'); +}); \ No newline at end of file diff --git a/src/parse/text/token/index.ts b/src/parse/text/token/index.ts new file mode 100644 index 0000000..fe39783 --- /dev/null +++ b/src/parse/text/token/index.ts @@ -0,0 +1,27 @@ +import type ParserOptions from '../../../types/options'; +import TokenType from '../../../types/token-types'; + +import Token, { type IToken } from '../../token'; + +export interface ITextToken extends IToken { + value?: string; +} + +export default class TextToken extends Token { + public value: string; + constructor(token: ITextToken = {}) { + if (token.value != null && typeof token.value !== 'string') { + throw new Error('TODO - ExpressionError: value must be a string'); + } + super({ + ...token, + type: TokenType.TEXT, + value: token.value == null ? '' : token.value + }); + } + + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + async evaluate(options: ParserOptions, meta: unknown) : Promise { + return this.value; + } +} \ No newline at end of file diff --git a/src/parse/text/tokenize/escape-block.ts b/src/parse/text/tokenize/escape-block.ts new file mode 100644 index 0000000..e8d43c4 --- /dev/null +++ b/src/parse/text/tokenize/escape-block.ts @@ -0,0 +1,78 @@ +import TokenType from '../../../types/token-types'; +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; +import ListToken from '../../list'; + +import TextToken from '../token'; + +import { tokenizeIf } from '../../if'; +import { tokenizeFunction } from '../../function'; + +import { ExpressionSyntaxError } from '../../../errors'; + +export default async (state: ITokenizeState) : Promise => { + let { tokens, cursor } = state; + const stack = state.stack; + + if (tokens[cursor]?.value !== '``') { + return false; + } + + const position = tokens[cursor].position; + + cursor += 1; + + if (cursor < (tokens.length - 1)) { + throw new ExpressionSyntaxError('unexpected end of expression'); + } + + const escTokens : Token[] = []; + while (cursor < tokens.length && tokens[cursor].value !== '``') { + + const mockState : ITokenizeState = { + options: { ...(state.options) }, + tokens, + cursor, + stack: [ ...stack, 'text-escape-block' ] + }; + + if ( + await tokenizeIf(mockState) || + await tokenizeFunction(mockState) + ) { + if (mockState.output) { + escTokens.push(mockState.output); + } + tokens = mockState.tokens; + cursor = mockState.cursor; + continue; + } + + // Treat everything else as plain text + if ( + escTokens.length === 0 || + escTokens[escTokens.length - 1].type != TokenType.TEXT + ) { + escTokens.push(new TextToken(tokens[cursor])); + + } else { + escTokens[escTokens.length - 1].value += tokens[cursor].value; + } + + cursor += 1; + } + + if (tokens[cursor].value !== '``') { + throw new ExpressionSyntaxError('unexpected end of expression'); + } + + state.tokens = tokens; + state.cursor = cursor + 1; + state.output = new ListToken({ + position, + value: escTokens + }); + + return true; +} \ No newline at end of file diff --git a/src/parse/text/tokenize/escape-single.spec.ts b/src/parse/text/tokenize/escape-single.spec.ts new file mode 100644 index 0000000..45a2e6c --- /dev/null +++ b/src/parse/text/tokenize/escape-single.spec.ts @@ -0,0 +1,148 @@ +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; +import TextToken from '../token'; +import tokenizeEscape from './escape-single'; + +const tokenBase : ITokenizeState = { + options: {}, + stack: [], + tokens: [], + cursor: 0 +}; + +test('Exports a function', () => { + expect(typeof tokenizeEscape).toBe('function'); +}); + +test('Returns false when theres no tokens', async () => { + expect.assertions(1); + const result = await tokenizeEscape(tokenBase); + expect(result).toBe(false); +}); + +test('Returns false when theres only one token', async () => { + expect.assertions(1); + const result = await tokenizeEscape({ + ...tokenBase, + tokens: [{position: 0, value: ''}] + }); + expect(result).toBe(false); +}); + +test('Returns false when there\'s only one token left', async () => { + expect.assertions(1); + const result = await tokenizeEscape({ + ...tokenBase, + tokens: [ + {position: 0, value: ''}, + {position: 0, value: ''} + ], + cursor: 1 + }); + expect(result).toBe(false); +}); + +test('Returns false when token at cursor is not \\', async () => { + expect.assertions(1); + const result = await tokenizeEscape({ + ...tokenBase, + tokens: [ + {position: 0, value: 'a'}, + {position: 0, value: 'n'} + ], + cursor: 0 + }); + expect(result).toBe(false); +}); + +test('Returns false when token isn\'t an escapable sequence', async () => { + expect.assertions(1); + const result = await tokenizeEscape({ + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: 'n'}], + cursor: 0 + }); + expect(result).toBe(false); +}); + +test('Returns true for default: \\\\', async () => { + expect.assertions(4); + const state : ITokenizeState = { + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: '\\'}], + cursor: 0 + }; + const result = await tokenizeEscape(state); + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('\\'); +}); + +test('Returns true for default: \\$', async () => { + expect.assertions(4); + const state : ITokenizeState = { + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: '$'}], + cursor: 0 + }; + const result = await tokenizeEscape(state); + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('$'); +}); + +test('Returns true for default: \\"', async () => { + expect.assertions(4); + const state : ITokenizeState = { + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: '"'}], + cursor: 0 + }; + const result = await tokenizeEscape(state); + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('"'); +}); + +test('Returns true for default: \\`', async () => { + expect.assertions(4); + const state : ITokenizeState = { + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: '`'}], + cursor: 0 + }; + const result = await tokenizeEscape(state); + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('`'); +}); + +test('Returns false for defaults when alternative list is specified', async () => { + expect.assertions(1); + const state : ITokenizeState = { + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: '$'}], + cursor: 0 + }; + const result = await tokenizeEscape(state, ['@']); + expect(result).toBe(false); +}); + +test('Uses alternative list of escapables when specified', async () => { + expect.assertions(4); + const state : ITokenizeState = { + ...tokenBase, + tokens: [{position: 0, value: '\\'}, {position: 0, value: '@'}], + cursor: 0 + }; + const result = await tokenizeEscape(state, ['@']); + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('@'); +}); \ No newline at end of file diff --git a/src/parse/text/tokenize/escape-single.ts b/src/parse/text/tokenize/escape-single.ts new file mode 100644 index 0000000..a3f37ed --- /dev/null +++ b/src/parse/text/tokenize/escape-single.ts @@ -0,0 +1,26 @@ +import type ITokenizeState from '../../../types/tokenize-state'; + +import TextToken from '../token'; + +export default async (state: ITokenizeState, characters?: string[]) : Promise => { + const { tokens, cursor } = state; + + if (characters == null) { + characters = ['\\', '$', '"', '`'] + } + + if ( + (cursor + 1) >= tokens.length || + tokens[cursor].value !== '\\' || + !characters.includes(tokens[cursor + 1].value) + ) { + return false; + } + + state.output = new TextToken({ + position: tokens[cursor].position, + value: tokens[cursor + 1].value + }); + state.cursor += 2; + return true; +} \ No newline at end of file diff --git a/src/parse/text/tokenize/quoted.ts b/src/parse/text/tokenize/quoted.ts new file mode 100644 index 0000000..e501200 --- /dev/null +++ b/src/parse/text/tokenize/quoted.ts @@ -0,0 +1,97 @@ +import TokenType from '../../../types/token-types'; +import type ITokenizeState from '../../../types/tokenize-state'; + +import { ExpressionSyntaxError } from '../../../errors'; + +import type Token from '../../token'; +import ListToken from '../../list'; + +import TextToken from '../token'; + +import tokenizeEscapeSingle from './escape-single'; +import tokenizeTextSpecial from './special'; + +import { tokenizeIf } from '../../if'; +import { tokenizeFunction } from '../../function'; + +export default async (state: ITokenizeState) : Promise => { + + let { tokens, cursor } = state; + const stack = state.stack; + + if (tokens[cursor]?.value !== '"') { + return false; + } + + const position = tokens[cursor]?.position; + + cursor += 1; + + if (cursor === tokens.length) { + throw new ExpressionSyntaxError('unexpected end of expression'); + } + + const quoteTokens : Token[] = []; + while (cursor < tokens.length && tokens[cursor].value !== '"') { + + const lastToken : Token = quoteTokens[quoteTokens.length - 1]; + + const mockState : ITokenizeState = { + options: {...(state.options)}, + tokens, + cursor, + stack: [...stack, 'text-quoted'] + }; + if ( + await tokenizeEscapeSingle(mockState, ['\\', '"']) || + await tokenizeTextSpecial(mockState) || + await tokenizeIf(mockState) || + await tokenizeFunction(mockState) + ) { + + if (mockState.output != null) { + if ( + lastToken && + lastToken.type === TokenType.TEXT && + (mockState.output).type === TokenType.TEXT + ) { + lastToken.value += (mockState.output).value; + } else { + quoteTokens.push(mockState.output); + } + } + tokens = mockState.tokens; + cursor = mockState.cursor; + continue; + } + + // Treat everything else as text + if (lastToken && lastToken.type === TokenType.TEXT) { + lastToken.value += tokens[cursor].value; + + } else { + quoteTokens.push(new TextToken({ + position: cursor, + value: tokens[cursor].value + })); + } + cursor += 1; + } + + if (cursor >= tokens.length) { + throw new ExpressionSyntaxError('unexpected end of expression'); + } + + if (tokens[cursor].value !== '"') { + throw new ExpressionSyntaxError('expected closing quote', tokens[cursor].position); + } + + state.tokens = tokens; + state.cursor = cursor + 2; + state.output = new ListToken({ + position, + value: quoteTokens + }); + + return true; +} \ No newline at end of file diff --git a/src/parse/text/tokenize/special.spec.ts b/src/parse/text/tokenize/special.spec.ts new file mode 100644 index 0000000..12a2c6c --- /dev/null +++ b/src/parse/text/tokenize/special.spec.ts @@ -0,0 +1,134 @@ +import type ITokenizeState from '../../../types/tokenize-state'; + +import type Token from '../../token'; +import TextToken from '../token'; + +import tokenizeSpecial from './special'; + +const tokenBase : ITokenizeState = { + options: {}, + tokens: [], + cursor: 0, + stack: [] +}; + +test('It exports a function', () => { + expect(typeof tokenizeSpecial).toBe('function'); +}); + +test('Returns false when options.specialSequences is false', async () => { + expect.assertions(1); + const result = await tokenizeSpecial({ + ...tokenBase, + options: { specialSequences: false } + }); + expect(result).toBe(false); +}); + +test('Returns false when theres no tokens', async () => { + expect.assertions(1); + const result = await tokenizeSpecial(tokenBase); + expect(result).toBe(false); +}); + +test('Returns false when theres only one token', async () => { + expect.assertions(1); + const result = await tokenizeSpecial({ + ...tokenBase, + tokens: [{position: 0, value: ''}] + }); + expect(result).toBe(false); +}); + +test('Returns false when there\'s only one token left', async () => { + expect.assertions(1); + const result = await tokenizeSpecial({ + ...tokenBase, + tokens: [ + {position: 0, value: ''}, + {position: 0, value: ''} + ], + cursor: 1 + }); + expect(result).toBe(false); +}); + +test('Returns false when token at cursor is not \\', async () => { + expect.assertions(1); + const result = await tokenizeSpecial({ + ...tokenBase, + tokens: [ + {position: 0, value: 'a'}, + {position: 0, value: 'n'} + ], + cursor: 0 + }); + expect(result).toBe(false); +}); + +test('Returns false when there isn\'t a special sequence', async () => { + expect.assertions(1); + const result = await tokenizeSpecial({ + ...tokenBase, + tokens: [ + {position: 0, value: '\\'}, + {position: 0, value: 'v'} + ], + cursor: 0 + }); + expect(result).toBe(false); +}); + +test('Parses \\n', async () => { + expect.assertions(4); + + const state : ITokenizeState = { + ...tokenBase, + tokens: [ + {position: 0, value: '\\'}, + {position: 1, value: 'n'} + ] + }; + const result = await tokenizeSpecial(state); + + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('\n'); +}); + +test('Parses \\r', async () => { + expect.assertions(4); + + const state : ITokenizeState = { + ...tokenBase, + tokens: [ + {position: 0, value: '\\'}, + {position: 1, value: 'r'} + ] + }; + const result = await tokenizeSpecial(state); + + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('\r'); +}); + +test('Parses \\t', async () => { + expect.assertions(4); + + const state : ITokenizeState = { + ...tokenBase, + tokens: [ + {position: 0, value: '\\'}, + {position: 1, value: 't'} + ] + }; + const result = await tokenizeSpecial(state); + + expect(result).toBe(true); + expect(state.output).toBeDefined(); + expect(state.output instanceof TextToken).toBe(true); + expect((state.output).value).toBe('\t'); +}); \ No newline at end of file diff --git a/src/parse/text/tokenize/special.ts b/src/parse/text/tokenize/special.ts new file mode 100644 index 0000000..cf4d07c --- /dev/null +++ b/src/parse/text/tokenize/special.ts @@ -0,0 +1,34 @@ +import has from '../../../helpers/has'; + +import type ITokenizeState from '../../../types/tokenize-state'; + +import TextToken from '../token'; + +export default async (state: ITokenizeState) : Promise => { + if (state.options.specialSequences === false) { + return false; + } + + const characters : Record = { + 'n': '\n', + 'r': '\r', + 't': '\t' + }; + + const { tokens, cursor } = state; + if ( + (cursor + 1) >= tokens.length || + tokens[cursor].value !== '\\' || + !has(characters, tokens[cursor + 1].value) + ) { + return false; + } + + state.output = new TextToken({ + position: tokens[cursor].position, + value: characters[tokens[cursor + 1].value] + }); + state.cursor += 2; + + return true; +} \ No newline at end of file diff --git a/src/parse/token.spec.ts b/src/parse/token.spec.ts new file mode 100644 index 0000000..4c8ce18 --- /dev/null +++ b/src/parse/token.spec.ts @@ -0,0 +1,95 @@ +import '../../jest/helpers'; + +import TokenType from '../types/token-types'; +import Token from './token'; + +test('Exports a constructor', () => { + expect(typeof Token).toBe('function'); + expect(Token.prototype).toBeDefined(); +}); + +test('Has .toJSON() function', () => { + expect(Token.prototype).toHaveOwnProperty('toJSON'); + expect(typeof Token.prototype.toJSON).toBe('function'); +}); + +test('Has .toString() function', () => { + expect(Token.prototype).toHaveOwnProperty('toString'); + expect(typeof Token.prototype.toString).toBe('function'); +}); + +test('Has .evaluate() function', () => { + expect(Token.prototype).toHaveOwnProperty('evaluate'); + expect(typeof Token.prototype.evaluate).toBe('function'); +}); + +test('Constructs without error', () => { + expect(() => new Token()).not.toThrow(); + expect(new Token()).toBeInstanceOf(Token); +}); + +test('Stores type correctly', () => { + const result1 = new Token(); + expect(result1).toHaveOwnProperty('type', TokenType.UNKNOWN); + + const result2 = new Token({ type: TokenType.TEXT }) + expect(result2).toHaveOwnProperty('type', TokenType.TEXT); +}); + +test('Stores position correctly', () => { + const result1 = new Token(); + expect(result1).toHaveOwnProperty('position', -1); + + const result2 = new Token({ position: 10 }) + expect(result2).toHaveOwnProperty('position', 10); +}); + +test('Stores value correctly', () => { + const result1 = new Token(); + expect(result1.value).toBeUndefined() + + const result2 = new Token({ value: 'test' }) + expect(result2).toHaveOwnProperty('value', 'test'); +}); + +test('.toJSON() returns proper representation', () => { + const result1 = (new Token()).toJSON(); + expect(result1).toHaveOwnProperty('type', TokenType.UNKNOWN); + expect(result1).toHaveOwnProperty('position', -1); + expect(result1).toHaveOwnProperty('value', null); + + const result2 = (new Token({ type: TokenType.TEXT, position: 0, value: 'test' })).toJSON(); + expect(result2).toHaveOwnProperty('type', TokenType.TEXT); + expect(result2).toHaveOwnProperty('position', 0); + expect(result2).toHaveOwnProperty('value', 'test'); +}); + +test('.toString() returns proper representation', () => { + const json = (new Token({ type: TokenType.TEXT, position: 0, value: 'test' })).toString(); + const result = JSON.parse(json); + + expect(result).toHaveOwnProperty('type', TokenType.TEXT); + expect(result).toHaveOwnProperty('position', 0); + expect(result).toHaveOwnProperty('value', 'test'); +}); + +test('.evaluate() throws unless token is empty', () => { + expect(() => { + const token = new Token(); + return token.evaluate({}, {}) + }).toAsyncThrow(); +}); + +test('.evaluate() does not throw if token is empty', () => { + expect(() => { + const token = new Token({type: TokenType.EMPTY}); + return token.evaluate({}, {}); + }).not.toAsyncThrow(); +}); + +test('.evaluate() returns undefined for empty token', async () => { + expect.assertions(1); + const token = new Token({type: TokenType.EMPTY}); + const result = await token.evaluate({}, {}); + expect(result).toBeUndefined(); +}); \ No newline at end of file diff --git a/src/parse/token.ts b/src/parse/token.ts new file mode 100644 index 0000000..c8112bd --- /dev/null +++ b/src/parse/token.ts @@ -0,0 +1,42 @@ +import type IParserOptions from '../types/options'; + +import TokenType from '../types/token-types'; + +export interface IToken { + type?: TokenType; + position?: number; + value?: unknown; +} + +export default class Token { + + public type : TokenType; + public position : number; + public value : unknown; + + constructor(token: IToken = {}) { + this.type = token.type == null ? TokenType.UNKNOWN : token.type; + this.position = token.position != null ? token.position : -1; + this.value = token.value; + } + + toJSON() : Record { + return { + type: this.type, + position: this.position, + value: this.value == null ? null : this.value + }; + } + + toString() : string { + return JSON.stringify(this.toJSON()); + } + + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + async evaluate(options: IParserOptions, meta: unknown) : Promise { + if (this.type !== TokenType.EMPTY) { + throw new Error('TODO - ExpressionError: token does not implement evaluate function'); + } + return; + } +} \ No newline at end of file diff --git a/src/tokens/arguments.js b/src/tokens/arguments.js deleted file mode 100644 index 8f14e5d..0000000 --- a/src/tokens/arguments.js +++ /dev/null @@ -1,94 +0,0 @@ -const types = require('../helpers/token-types.js'); - -const { removeWhitespace } = require('../helpers/misc.js'); - - -const { ExpressionSyntaxError } = require('../errors.js'); -const { tokenizeEscape, tokenizeQuote, TextToken } = require('./text.js'); -const blockEscapeHandler = require('./block-escape.js'); - -const ifHandler = require('./if.js'); -const varHandler = require('./variable.js'); - -// tokenizeArguments(); -module.exports.tokenize = (output, tokens) => { - if (!tokens.length || tokens[0].value !== '[') { - return false; - } - - const openToken = tokens.shift(); - removeWhitespace(tokens); - - let parts = []; - while (tokens.length) { - let position = tokens[0].position, - whitespace = removeWhitespace(tokens); - - // End of arguments list - if (tokens[0].value === ']') { - tokens.shift(); - if (!parts.length) { - parts = [new TextToken({position, value: ''})] - } - output.push(parts); - return true; - } - - // End of argument - if (tokens[0].value === ',') { - tokens.shift(); - removeWhitespace(tokens); - if (!parts.length) { - parts = [new TextToken({position, value: ''})]; - } - output.push(parts); - parts = []; - continue; - } - - if (blockEscapeHandler.tokenize(parts, tokens)) { - continue; - } - - // Add whitespace to argument part's list - if (whitespace) { - if (parts.length && parts[parts.length - 1].type === types.TEXT) { - parts[parts.length - 1].value += whitespace; - - } else { - parts.push(new TextToken({position, value: whitespace})); - } - } - - // Consume tokens - if (tokenizeEscape(parts, tokens, '"$,\\]')) { - continue; - } - - if (tokenizeQuote(parts, tokens)) { - continue; - } - - if (ifHandler.tokenize(parts, tokens)) { - continue; - } - - if (varHandler.tokenize(parts, tokens)) { - continue; - } - - // Consume all other tokens as text - const token = tokens.shift(); - if (parts.length && parts[parts.length - 1].type === types.TEXT) { - parts[parts.length - 1].value += token.value; - } else { - parts.push(new TextToken(token)); - } - } - - - if (!tokens.length) { - throw new ExpressionSyntaxError('Unexpected end of expression', openToken.position); - } - throw new ExpressionSyntaxError('expected end of variable arguments', openToken.position); -}; \ No newline at end of file diff --git a/src/tokens/base.js b/src/tokens/base.js deleted file mode 100644 index c738fae..0000000 --- a/src/tokens/base.js +++ /dev/null @@ -1,16 +0,0 @@ -const types = require('../helpers/token-types.js'); - -module.exports = class Token { - - constructor({type, position, value}) { - this.type = type || types.UNKNOWN; - this.position = position == null ? -1 : position; - if (value != null) { - this.value = value; - } - } - - evaluate() { - return this.value == null ? '' : this.value; - } -} \ No newline at end of file diff --git a/src/tokens/block-escape.js b/src/tokens/block-escape.js deleted file mode 100644 index 17176bf..0000000 --- a/src/tokens/block-escape.js +++ /dev/null @@ -1,67 +0,0 @@ -const types = require('../helpers/token-types.js'); - -const { TextToken } = require('./text.js'); - -const ifHandler = require('./if.js'); -const variableHandler = require('./variable.js'); - -/** - * - * @param {Array} output - * @param {string[]} tokens - * @returns - */ -const tokenize = (output, tokens) => { - if ( - output.length > 0 || - !tokens.length || - tokens[0].value !== '``' - ) { - return false; - } - - // copy tokens list, remove opening `` - let tokensCopy = tokens.slice(1); - // tokensCopy.shift(); - - let result = []; - while (tokensCopy.length) { - if (tokensCopy[0].value === '``') { - break; - } - - if (ifHandler.tokenize(result, tokensCopy)) { - continue; - } - if (variableHandler.tokenize(result, tokensCopy)) { - continue; - } - - if (result.length && result[result.length - 1].type === types.TEXT) { - result[result.length - 1].value += tokensCopy.shift().value; - } else { - tokensCopy[0].type = types.TEXT; - result.push(new TextToken(tokensCopy.shift())) - } - } - - // Remove closing `` - if (!tokensCopy.length || tokensCopy[0].value !== '``') { - return false; - } - tokensCopy.shift(); - - // Escape block not the only token in the argument - while (tokensCopy.length && tokensCopy[0].value === ' ') { - tokensCopy.shift(); - } - if (!tokensCopy.length || (tokensCopy[0].value !== ',' && tokensCopy[0].value !== ']')) { - return false; - } - - tokens.splice(0, tokens.length - tokensCopy.length); - output.push(...result); - return true; -}; - -module.exports.tokenize = tokenize; \ No newline at end of file diff --git a/src/tokens/comparison.js b/src/tokens/comparison.js deleted file mode 100644 index 91a392c..0000000 --- a/src/tokens/comparison.js +++ /dev/null @@ -1,142 +0,0 @@ -const types = require('../helpers/token-types.js'); - -const { removeWhitespace } = require('../helpers/misc.js'); -const operators = require('../operators/compare.js'); - -const BaseToken = require('./base.js'); -const variableHandler = require('./variable.js'); -const ifHandler = require('./if.js'); -const { - TextToken, - tokenizeEscape, - tokenizeQuote -} = require('./text.js'); - -class ComparisonToken extends BaseToken { - - constructor(options) { - super({ - ...options, - type: types.CONDITION - }); - this.arguments = options.arguments; - } - - async evaluate(options) { - if (!this.value) { - this.value = 'exists'; - } - const operator = operators.get(this.value); - - if (operator == null) { - return false; - } - - let args = []; - if (this.arguments && this.arguments.length) { - for (let idx = 0; idx < this.arguments.length; idx += 1) { - let accumulator = ''; - const parts = this.arguments[idx]; - for (let partsIdx = 0; partsIdx < parts.length; partsIdx += 1) { - let res = await parts[partsIdx].evaluate(options); - if (res != null) { - accumulator += res; - } - } - args.push(accumulator); - } - } - - if (options.onlyValidate) { - return false; - } - - return operator(...args); - } -} - -// tokenizeComparison() -module.exports.tokenize = (tokens) => { - - // nothing to consume - if (!tokens.length || tokens[0].value === ',' || tokens[0].value === ']') { - return; - } - - const leadingWs = removeWhitespace(tokens), - position = tokens[0].position, - left = [], - right = []; - - let value; - while (tokens.length) { - const pos = tokens[0].position, - ws = removeWhitespace(tokens); - - // end of condition block - if (!tokens.length || tokens[0].value === ',' || tokens[0].value === ']') { - break; - } - - // consume operator: must be prefixed with whitespace and suffixed with whitespace or end-of-conditional - if ( - value == null && - (leadingWs || ws) && - operators.has(tokens[0].value) && - ( - !tokens[1] || - tokens[1].value === ' ' || - tokens[1].value === ',' || - tokens[1].value === ']' - ) - ) { - value = tokens[0].value; - tokens.shift(); - removeWhitespace(tokens); - continue; - } - - const side = value == null ? left : right; - - // Add whitespace to side token array - if (ws) { - if (side.length && side[side.length - 1].type === types.TEXT) { - side[side.length - 1].value += ws; - } else { - side.push(new TextToken({value: ws, position: pos})); - } - } - - if (tokenizeEscape(side, tokens)) { - continue; - } - - if (tokenizeQuote(side, tokens)) { - continue; - } - - if (ifHandler.tokenize(side, tokens)) { - continue; - } - - if (variableHandler.tokenize(side, tokens)) { - continue; - } - - // Treat all other tokens as plain text - const token = tokens.shift(); - if (side.length && side[side.length - 1].type === types.TEXT) { - side[side.length - 1].value += token.value; - } else { - side.push(new TextToken(token)); - } - } - - return new ComparisonToken({ - position, - value, - arguments: [left, right] - }); -}; - -module.exports.ComparisonToken = ComparisonToken; \ No newline at end of file diff --git a/src/tokens/if.js b/src/tokens/if.js deleted file mode 100644 index f659fa5..0000000 --- a/src/tokens/if.js +++ /dev/null @@ -1,159 +0,0 @@ -const types = require('../helpers/token-types.js'); -const { removeWhitespace } = require('../helpers/misc.js'); - -const { ExpressionSyntaxError } = require('../errors.js'); - -const BaseToken = require('./base.js'); -const comparisonHandler = require('./comparison.js'); -const logicOperatorHandler = require('./logic-operator.js'); -const argumentsHandler = require('./arguments.js'); - -class IfToken extends BaseToken { - constructor(options) { - super({ - type: types.IF, - ...options - }); - this.condition = options.condition; - this.arguments = options.arguments; - } - - async evaluate(options = {}) { - let result = await this.condition.evaluate(options); - - const args = []; - if (this.arguments && this.arguments.length) { - for (let idx = 0; idx < this.arguments.length; idx += 1) { - let accumulator = ''; - const parts = this.arguments[idx]; - for (let partsIdx = 0; partsIdx < parts.length; partsIdx += 1) { - let res = await parts[partsIdx].evaluate(options); - if (res != null) { - accumulator += res; - } - } - args.push(accumulator); - } - } - - // Only validating: validate both arguments - if (options.onlyValidate) { - const args = []; - if (this.arguments && this.arguments.length) { - for (let idx = 0; idx < this.arguments.length; idx += 1) { - let accumulator = ''; - const parts = this.arguments[idx]; - for (let partsIdx = 0; partsIdx < parts.length; partsIdx += 1) { - let res = await parts[partsIdx].evaluate(options); - if (res != null) { - accumulator += res; - } - } - args.push(accumulator); - } - } - return ''; - } - - // No arguments - if (!this.arguments || !this.arguments.length) { - return ''; - } - - // Evaluate conditional argument - if (result) { - let accumulator = ''; - const parts = this.arguments[0]; - for (let partsIdx = 0; partsIdx < parts.length; partsIdx += 1) { - let res = await parts[partsIdx].evaluate(options); - if (res != null) { - accumulator += res; - } - } - return accumulator; - - } else if (this.arguments[1] == null) { - return ''; - - } else { - let accumulator = ''; - const parts = this.arguments[1]; - for (let partsIdx = 0; partsIdx < parts.length; partsIdx += 1) { - let res = await parts[partsIdx].evaluate(options); - if (res != null) { - accumulator += res; - } - } - return accumulator; - } - } -} - -// tokenizeIf(); -module.exports.tokenize = (output, tokens) => { - - // not an $if[ token - if ( - !tokens.length || - tokens.length < 2 || - tokens[0].value !== '$' || - tokens[1].value !== 'if' - ) { - return false; - } - - if (!tokens[2] || tokens[2].value !== '[') { - throw new ExpressionSyntaxError('$if requires atleast 2 arguments', tokens[1].position); - } - - const position = tokens[0].position; - const args = []; - - // remove opening tokens - tokens.splice(0, 2); - - // Save opening bracket token - const openToken = tokens.shift(); - - // Attempt to consume logic condition - let condition = logicOperatorHandler.tokenize(tokens); - if (!condition) { - - // Attempt to consume comparison condition - condition = comparisonHandler.tokenize(tokens); - if (!condition) { - throw new ExpressionSyntaxError('$if requires the first argument to be a conditional', openToken.position + 1); - } - } - - // Comsume delimiter(,) following condition - if (!tokens.length) { - throw new ExpressionSyntaxError('unexpected end of expression'); - } - if (tokens[0].value !== ',') { - throw new ExpressionSyntaxError('expected comma delimiter after condition', tokens[0].position); - } - tokens.shift(); - removeWhitespace(tokens); - - // Re-add opening bracket token so tokenizeArguments() can be used to finish parsing the $if[] - tokens.unshift(openToken); - argumentsHandler.tokenize(args, tokens); - - // check result - if (args.length < 1) { - throw new ExpressionSyntaxError('$if requires at least 2 arguments', openToken.position); - } - if (args.length > 2) { - throw new ExpressionSyntaxError('$if requires at most 3 arguments', args[3].position); - } - - output.push(new IfToken({ - position, - condition, - arguments: args - })); - return true; -}; - -module.exports.IfToken = IfToken; \ No newline at end of file diff --git a/src/tokens/index.js b/src/tokens/index.js deleted file mode 100644 index cf5399f..0000000 --- a/src/tokens/index.js +++ /dev/null @@ -1,52 +0,0 @@ - -const types = require('../helpers/token-types.js'); - -const { tokenize } = require('../helpers/split.js'); - -// const { tokenizeEscape, tokenizeQuote, TextToken } = require('./text.js'); -const { tokenizeEscape, TextToken } = require('./text.js'); -const ifHandler = require('./if.js'); -const variableHandler = require('./variable.js'); - -// tokenize(expression) -module.exports = expression => { - let tokens = tokenize(expression); - const result = []; - - while (tokens.length) { - - // Attempt to consume token as escape sequence - if (tokenizeEscape(result, tokens)) { - continue; - } - - /* - - // Attempt to consume token as quoted text - if (tokenizeQuote(result, tokens)) { - continue; - } - */ - - // Attempt to consume token as $if - if (ifHandler.tokenize(result, tokens)) { - continue; - } - - // Attempt to consume token as a variable - if (variableHandler.tokenize(result, tokens)) { - continue; - } - - // Assume token is literal text - let token = tokens.shift(); - - if (result.length && result[result.length - 1].type === types.TEXT) { - result[result.length - 1].value += token.value; - - } else { - result.push(new TextToken(token)); - } - } - return result; -}; \ No newline at end of file diff --git a/src/tokens/logic-operator.js b/src/tokens/logic-operator.js deleted file mode 100644 index fc8772d..0000000 --- a/src/tokens/logic-operator.js +++ /dev/null @@ -1,104 +0,0 @@ -const types = require('../helpers/token-types.js'); - -const { ExpressionSyntaxError } = require('../errors.js'); -const { removeWhitespace } = require('../helpers/misc.js'); - -const BaseToken = require('./base.js'); -const comparisonHandler = require('./comparison.js'); - -const operators = require('../operators/logical.js'); - -class LogicToken extends BaseToken { - constructor(options) { - super({ - ...options, - type: types.LOGICAL - }); - this.arguments = options.arguments; - } - - async evaluate(options = {}) { - let operator = operators.get(this.value); - if (!operator) { - return false; - } - - let args = []; - for (let idx = 0; idx < this.arguments.length; idx += 1) { - let arg = await this.arguments[idx].evaluate(options); - args.push(arg); - } - - if (options.onlyValidate) { - return false; - } - return operator(...args); - } -} - -// tokenizeLogicOperator() -const tokenize = tokens => { - // Not a logical operator - if ( - tokens.length < 4 || - tokens[0].value !== '$' || - !operators.has('$' + tokens[1].value) || - tokens[2].value !== '[' - ) { - return; - } - - - // setup result token - const result = { - position: tokens[0].position, - value: '$' + tokens[1].value, - arguments: [] - } - - // Remove opening tokens: $ operator [ - tokens.splice(0, 3); - - while (tokens.length) { - - // Trim leading whitespace - removeWhitespace(tokens); - if (!tokens.length) { - break; - } - - // store start position - let position = tokens[0].position; - - // Consume condition and trailing whitespace - let token = tokenize(tokens); - if (token == null) { - token = comparisonHandler.tokenize(tokens); - if (token == null) { - throw new ExpressionSyntaxError('condition expected', position); - } - } - result.arguments.push(token); - removeWhitespace(tokens); - if (!tokens.length) { - break; - } - - // Argument delimiter - if (tokens[0].value === ',') { - tokens.shift(); - continue; - } - - // End of Logic Block - if (tokens[0].value === ']') { - tokens.shift(); - removeWhitespace(tokens); - return new LogicToken(result); - } - } - - throw new ExpressionSyntaxError('unexpected end of expression'); -}; -module.exports.tokenize = tokenize; -module.exports.LogicToken = LogicToken; \ No newline at end of file diff --git a/src/tokens/text.js b/src/tokens/text.js deleted file mode 100644 index 383c350..0000000 --- a/src/tokens/text.js +++ /dev/null @@ -1,114 +0,0 @@ -const { ExpressionSyntaxError } = require('../errors.js'); -const types = require('../helpers/token-types.js'); - -const BaseToken = require('./base.js'); - -class TextToken extends BaseToken { - constructor(options) { - super({ - ...options, - type: types.TEXT - }); - } -} - -const tokenizeEscape = (output, tokens, escape) => { - if (!tokens.length || tokens[0].value !== '\\') { - return false; - } - - if (escape == null) { - escape = '"$[\\rnt'; - } - - // get escape denoter character(\) - let token = tokens.shift(); - - // Denoter followed by non-escapable character - Treat as plain text - if ( - tokens[0] == null || - escape.indexOf(tokens[0].value[0]) === -1 - ) { - if (output[1] != null && output[output.length - 1].type === types.TEXT) { - output[output.length - 1].value += token.value; - } else { - output.push(new TextToken(token)); - } - return true; - } - - // Get escaped token - token = tokens.shift(); - - // Escaped token contains more than one character - // split escaped character from remaining token text - if (token.length > 1) { - tokens.unshift({ - position: token.position, - value: token.value.slice(1) - }); - token.value = token.value[0]; - } - - // If token is special-character-sequence - // replace sequence with represented value - if (token.value === 'n') { - token.value = '\n'; - } else if (token.value === 'r') { - token.value = '\r'; - } else if (token.value === 't') { - token.value = '\t'; - } - - // If the last token of the output is text, append the token value to the text - if (output.length && output[output.length - 1].type === types.TEXT) { - output[output.length - 1].value += token.value; - - // Otherwise add a new text token to the output - } else { - output.push(new TextToken(token)); - } - return true; -}; - -const tokenizeQuote = (output, tokens) => { - if (!tokens.length || tokens[0].value !== '"') { - return false; - } - - const openToken = tokens.shift(); - - let text = []; - while (tokens.length) { - if (tokens[0].value === '"') { - tokens.shift(); - text = text.map(item => item.value).join(''); - - if (output.length && output[output.length - 1].type === types.TEXT) { - output[output.length - 1].value += text; - - } else { - output.push(new TextToken({ - position: openToken.position + 1, - value: text - })); - } - return true; - } - - if (tokenizeEscape(text, tokens, '\\"nrt')) { - continue; - } - - text.push(tokens.shift()); - } - - // End quote wasn't encountered in the loop - throw new ExpressionSyntaxError('end quote missing', openToken.position); -}; - -module.exports = { - tokenizeEscape, - tokenizeQuote, - TextToken -}; \ No newline at end of file diff --git a/src/tokens/variable.js b/src/tokens/variable.js deleted file mode 100644 index e3d50e8..0000000 --- a/src/tokens/variable.js +++ /dev/null @@ -1,103 +0,0 @@ -const { ExpressionVariableError, ExpressionArgumentsError } = require('../errors.js'); - -const types = require('../helpers/token-types.js'); - -const BaseToken = require('./base.js'); -const argumentsHandler = require('./arguments.js'); - -const nameCheck = /^([a-z][a-z\d]+)([\s\S]*)$/i; - -class VariableToken extends BaseToken { - constructor(options) { - super({ - ...options, - type: types.VARIABLE - }); - this.arguments = options.arguments; - } - - async evaluate(options = {}) { - if (!options.handlers || !options.handlers.has(this.value)) { - throw new ExpressionVariableError(`unknown variable`, this.position, this.value); - } - - const variable = options.handlers.get(this.value); - - if (variable.triggers) { - let trigger = variable.triggers[options.trigger.type], - display = options.trigger.type ? options.trigger.type.toLowerCase() : "unknown trigger"; - - if (trigger == null || trigger === false) { - throw new ExpressionVariableError(`$${this.value} does not support being triggered by: ${display}`, this.position, this.value); - } - - if (Array.isArray(trigger)) { - if (!trigger.some(id => id === options.trigger.id)) { - throw new ExpressionVariableError(`$${this.value} does not support this specific trigger type: ${display}`, this.position, this.value); - } - } - } - - let args = []; - if (this.arguments && this.arguments.length) { - for (let idx = 0; idx < this.arguments.length; idx += 1) { - const parts = this.arguments[idx]; - let accumulator = ''; - for (let partIdx = 0; partIdx < parts.length; partIdx += 1) { - let part = await parts[partIdx].evaluate(options); - if (part != null) { - accumulator += part; - } - } - args.push(accumulator); - } - } - if (options.onlyValidate) { - return ''; - } - - try { - if (variable.argsCheck) { - await variable.argsCheck(...args); - } - } catch (err) { - throw new ExpressionArgumentsError(err.message, err.position, err.index); - } - const result = await variable.evaluator(options.metadata || {}, ...args); - return result == null ? '' : result; - } -} - -// tokenizeVariable() -module.exports.tokenize = (output, tokens) => { - - let nameMatch; - if ( - tokens.length < 2 || - tokens[0].value !== '$' || - !(nameMatch = nameCheck.exec(tokens[1].value)) - ) { - return false; - } - tokens.shift(); - - const token = tokens.shift(); - - // trailing character after variable name - if (nameMatch[2] !== '') { - tokens.unshift({ - value: nameMatch[2], - position: token.position + nameMatch[1].length - }); - token.value = nameMatch[1]; - } - - const args = []; - if (argumentsHandler.tokenize(args, tokens)) { - token.arguments = args; - } - - output.push(new VariableToken(token)) - return true; -}; -module.exports.VariableToken = VariableToken; \ No newline at end of file diff --git a/src/types/manifest-comparison.ts b/src/types/manifest-comparison.ts new file mode 100644 index 0000000..e7c1f87 --- /dev/null +++ b/src/types/manifest-comparison.ts @@ -0,0 +1,13 @@ +export const enum ArgumentQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED +} + +export default interface ComparatorManifest { + arguments: ArgumentQuantifier; + description: string; + casing?: boolean; + alias: string[]; + inverse: false | {description: string, alias: string[]} +} \ No newline at end of file diff --git a/src/types/options.ts b/src/types/options.ts new file mode 100644 index 0000000..7566aa7 --- /dev/null +++ b/src/types/options.ts @@ -0,0 +1,73 @@ +export type IMeta = Record; + +export interface IFunctionHandler { + /** When true argument evaluation will defer to handling functions */ + defer?: boolean; + stackCheck?: (options: IEvaluateOptions, meta: IMeta, stack: string[]) => Promise; + argsCheck?: (options: IEvaluateOptions, meta: IMeta, ...args: unknown[]) => Promise; + evaluate: (options: IEvaluateOptions, meta: IMeta, ...args: unknown[]) => Promise; +} + +export type IFunctionLookup = (name: string, stack?: string[], meta?: unknown) => Promise; + +export default interface IParserOptions { + functionHandlers?: Record; + functionLookups?: Record; + + "if"?: boolean; + eol?: 'error' | 'remove' | 'space' | 'keep'; + specialSequences?: boolean; + + verifyOnly?: boolean; + skipStackCheck?: boolean; + skipArgumentsCheck?: boolean; + + stack?: string[]; +} + +export const enum OperatorQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED, + PREBLOCK, + BLOCK +} + +export type IOperatorEvaluate = (options: IExpressionOptions, meta: IMeta, ...args: unknown[]) => Promise; + +export interface IOperatorDefinition { + signifier: string | string[]; + quantifier: OperatorQuantifier; + cased?: boolean; + defer?: boolean; + inverse?: { + signifier?: string | string[]; + evaluator?: IOperatorEvaluate; + }; + evaluate: IOperatorEvaluate; +} + +export interface IOperatorList { + disposition?: 'append' | 'replace'; + operators: IOperatorDefinition[]; +} + +export type ILookupHandler = (options: IExpressionOptions, meta: IMeta, stack: string[], name: string) => Promise; + +export interface IExpressionOptions { + eol?: 'error' | 'remove' | 'space' | 'keep'; + specialSequences?: boolean | Record; + + functionHandlers?: boolean | Record; + lookupHandlers?: boolean | Record; + + comparisonOperators?: boolean | IOperatorList; + blockOperators?: boolean | IOperatorList; +} + + +export interface IEvaluateOptions { + verifyOnly?: boolean; + skipStackChecks?: boolean; + skipArgumentsChecks?: boolean; +} \ No newline at end of file diff --git a/src/types/pre-token.ts b/src/types/pre-token.ts new file mode 100644 index 0000000..bb73f4e --- /dev/null +++ b/src/types/pre-token.ts @@ -0,0 +1,4 @@ +export default interface IPreToken { + position: number; + value: string; +} \ No newline at end of file diff --git a/src/types/token-types.ts b/src/types/token-types.ts new file mode 100644 index 0000000..2f16e61 --- /dev/null +++ b/src/types/token-types.ts @@ -0,0 +1,15 @@ +const enum TokenType { + UNKNOWN, + EXPRESSION, + LIST, + IFSTATEMENT, + FUNCTION, + TEXT, + ARGUMENT, + OPERATOR, + LOGICAL, + COMPARISON, + EMPTY +} + +export default TokenType; \ No newline at end of file diff --git a/src/types/tokenize-state.ts b/src/types/tokenize-state.ts new file mode 100644 index 0000000..8a8b31d --- /dev/null +++ b/src/types/tokenize-state.ts @@ -0,0 +1,11 @@ +import type ParserOptions from './options'; +import type IPreToken from './pre-token'; +import type Token from '../parse/token'; + +export default interface ITokenizeState { + options: ParserOptions, + tokens: IPreToken[]; + cursor: number; + stack: Array; + output?: Token | Token[]; +} \ No newline at end of file diff --git a/src2/expressionish/index.ts b/src2/expressionish/index.ts new file mode 100644 index 0000000..74fdaa9 --- /dev/null +++ b/src2/expressionish/index.ts @@ -0,0 +1,28 @@ + +export default class Expressionish { + + private functionDenoter : string; + private specialDenoter : string; + + private groupingDenoter : IGroupDenoterQuantified; + private quotesDenoters : IQuotesQuantified[]; + + private endofline : IEndOfLineQuantified; + + constructor(options) { + + } + + registerOperator() {} + registerOperators() {} + + registerFunctionHandler() {} + registerFunctionHandlers() {} + + registerLookupHandler() {} + registerLookupHandlers() {} + + tokenize() {} + + toJSON() {} +} \ No newline at end of file diff --git a/src2/index.ts b/src2/index.ts new file mode 100644 index 0000000..6d0122f --- /dev/null +++ b/src2/index.ts @@ -0,0 +1,12 @@ +export { + ExpressionError, + ExpressionOptionsError, + ExpressionFunctionError, + ExpressionStackError, + ExpressionArgumentsError +} from './errors/index'; + +export { + default, + default as Expressionish +} from './expressionish/' \ No newline at end of file diff --git a/src2/types/global.d.ts b/src2/types/global.d.ts new file mode 100644 index 0000000..cb05f22 --- /dev/null +++ b/src2/types/global.d.ts @@ -0,0 +1,20 @@ +declare type RequireAtLeastOne = { [K in keyof T]-?: Required> & Partial>>; }[keyof T]; + +declare type IMeta = Record; + +declare enum OperatorQuantifier { + LEFTONLY, + RIGHTOPTIONAL, + RIGHTREQUIRED, + PREBLOCK, + POSTBLOCK +} + +declare enum TokenType { + UNKNOWN, + EMPTY, + TEXT, + LIST, + FUNCTION, + CONDITION +} \ No newline at end of file diff --git a/test/evaluate.js b/test/evaluate.js deleted file mode 100644 index 0f199e5..0000000 --- a/test/evaluate.js +++ /dev/null @@ -1,351 +0,0 @@ -/* global describe, it */ - -const assert = require('assert'); - -const errors = require('../src/errors.js'); - -const evaluate = require('../src/evaluate.js'); - -const expectThrow = async (fnc, type) => { - try { - await fnc(); - } catch (err) { - if (type && !(err instanceof type)) { - console.log(err); - throw new Error(`threw incorrect error: ${err.name}`); - } - return; - } - throw new Error('did not throw an error'); -}; - -const expectEqual = async (fnc, value) => { - let result = await fnc(); - assert.equal(result, value); -}; - -const vars = new Map([ - ['txt', {handle: 'txt', argsCheck: () => {}, evaluator: () => 'evaled_var_text'}], - ['ten', {handle: 'ten', argsCheck: () => {}, evaluator: () => 10}], - ['sum', {handle: 'sum', argsCheck: () => {}, evaluator: (meta, ...args) => { - return args.map(item => Number(item)).reduce((acc, cur) => acc + cur, 0); - }}], - ['inout', {handle: 'inout', argsCheck: () => {}, evaluator: (meta, ...args) => { - return args.join(''); - }}] -]); -const options = { - handlers: vars, - trigger: '' -}; - -describe('evaluate()', function () { - - describe('Throws an error when arguments\'', function () { - it('option is undefined or null', async function () { - await expectThrow(() => evaluate(), TypeError); - }); - it('variable-handlers is undefined', async function () { - await expectThrow(() => evaluate({}), TypeError); - }); - it('variable-handlers is not a Map', async function () { - await expectThrow(() => evaluate({handlers: ''}), TypeError); - }); - it('options.trigger is undefined', async function () { - await expectThrow(() => evaluate({handlers: vars}), TypeError); - }); - it('options.trigger is null', async function () { - await expectThrow(() => evaluate({handlers: vars, trigger: null}), TypeError); - }); - it('options.expression is undefined', async function () { - await expectThrow(() => evaluate({handlers: vars, trigger: ''}), TypeError); - }); - it('options.expression is not a string', async function () { - await expectThrow(() => evaluate({handlers: vars, trigger: '', expression: true}), TypeError); - }); - }); - - describe('Input is empty string', function () { - it('does not throw an error', async function () { - await evaluate({...options, expression: ''}); - }); - it('returns a string', async function () { - let result = await evaluate({...options, expression: ''}); - assert.equal(typeof(result), 'string'); - }); - it('string is empty', async function () { - await expectEqual(() => evaluate({...options, expression: ''}), ''); - }); - }); - - describe('Input is plain text', function () { - it('does not throw an error', async function () { - await evaluate({...options, expression: 'plain text'}); - }); - it('returns a string', async function () { - let result = await evaluate({...options, expression: 'plain text'}); - assert.equal(typeof(result), 'string'); - }); - it('string matches input', async function () { - await expectEqual(() => evaluate({...options, expression: 'plain text'}) , 'plain text'); - }); - it('treats root-level quotes as literals', async function () { - await expectEqual(() => evaluate({...options, expression: '"text"'}), '"text"'); - }); - it('treats root-level double backticks as literals', async function () { - await expectEqual(() => evaluate({...options, expression: '``text``'}), '``text``'); - }); - }); - - describe('Input is escape sequences', function () { - it('Escapes \\\\', async function () { - await expectEqual(() => evaluate({...options, expression: '\\\\'}), '\\'); - }); - it('Escapes \\$', async function () { - await expectEqual(() => evaluate({...options, expression: '\\$'}), '$'); - }); - it('Escapes \\"', async function () { - await expectEqual(() => evaluate({...options, expression: '\\"'}), '"'); - }); - it('Treats \\ at the end of an expression as a literal', async function () { - await expectEqual(() => evaluate({...options, expression: '\\'}), '\\'); - }); - }); - - describe('Input is a mix of text', async function () { - it('Plain-text and escape sequences', async function () { - await expectEqual(() => evaluate({...options, expression: 'text\\\\'}), 'text\\'); - await expectEqual(() => evaluate({...options, expression: '\\\\text'}), '\\text'); - await expectEqual(() => evaluate({...options, expression: 'text\\\\text'}), 'text\\text'); - await expectEqual(() => evaluate({...options, expression: '\\\\text\\\\'}), '\\text\\'); - }); - it('Treats non-escape-sequences as literal \\', async function () { - await expectEqual(() => evaluate({...options, expression: '\\a'}), '\\a'); - }); - }); - - describe('Input is variable', function () { - it('Treats naked $ as text', async function () { - await expectEqual(() => evaluate({...options, expression: '$'}), '$'); - }); - it('Treats $ as text', async function () { - await expectEqual(() => evaluate({...options, expression: '$10'}), '$10'); - }); - it('Throws an error if the variable does not exist', async function () { - await expectThrow(() => evaluate({...options, expression: '$notdefined'}), errors.ExpressionVariableError); - }); - it('Evaluates variable', async function () { - await expectEqual(() => evaluate({...options, expression: '$txt'}), 'evaled_var_text'); - }); - it('Evaluates variable with arguments', async function () { - await expectEqual(() => evaluate({...options, expression: '$sum[1,2]'}), '3'); - }); - it('Evaluates nested variables', async function () { - await expectEqual(() => evaluate({...options, expression: '$sum[$ten, 1]'}), '11'); - }); - it('Evaluates nested variable with arguments', async function () { - await expectEqual(() => evaluate({...options, expression: '$sum[$sum[$ten, 1], 1]'}), '12'); - }); - it('Evaluates quoted text in arguments to plain text', async function () { - await expectEqual(() => evaluate({...options, expression: '$inout["text"]'}), 'text'); - }); - it('Block-escapes text in double backticks', async function () { - await expectEqual(() => evaluate({...options, expression: '$inout[``"text"``]'}), '"text"'); - }); - it('Evaluates vars in block escapes', async function () { - await expectEqual(() => evaluate({...options, expression: '$inout[``"$ten"``]'}), '"10"'); - }); - }); - - describe('Input is $if', function () { - it('throws an error if no arguments', async function () { - await expectThrow(() => evaluate({...options, expression: '$if'}), errors.ExpressionSyntaxError); - }); - it('Does not throw an error for valid statement', async function () { - await evaluate({...options, expression: '$if[1 === 1, true, false]'}); - }); - }); - - describe('Input is $if with comparison operator', function () { - it('Properly evaluates ===', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 === 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 === 2, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1.0 === 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a === a, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a === b, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a === A, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ === , yes, no]'}), 'yes'); - }); - it('Properly evaluates !==', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 !== 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 !== 2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1.0 !== 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a !== a, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a !== b, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a !== A, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ !== , yes, no]'}), 'no'); - }); - it('Properly evaluates ==', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 == 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1.0 == 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a == a, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a == A, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 == 2, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a == b, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ == , yes, no]'}), 'yes'); - }); - it('Properly evaluates !=', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 != 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1.0 != 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a != a, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a != A, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 != 2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a != b, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ != , yes, no]'}), 'no'); - }); - it('Properly evaluates <', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 < 2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1.0 < 2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 < 2.0, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 < 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a < 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 < a, yes, no]'}), 'no'); - }); - it('Properly evaluates <=', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 <= 2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1.0 <= 2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 <= 2.0, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 <= 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a < 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 < a, yes, no]'}), 'no'); - }); - it('Properly evaluates >', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[2 > 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[2.0 > 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[2 > 1.0, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 > 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a > 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 > a, yes, no]'}), 'no'); - }); - it('Properly evaluates >=', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[2 >= 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[2.0 >= 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[2 >= 1.0, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 >= 1, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a > 1, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 > a, yes, no]'}), 'no'); - }); - it('Properly evaluates exists', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[a exists, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ exists, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if["" exists, yes, no]'}), 'no'); - }); - it('Properly evaluates !exists', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[a !exists, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ !exists, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if["" !exists, yes, no]'}), 'yes'); - }); - it('Properly evaluates isnumber', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[.1 isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1.1 isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[-1 isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[-.1 isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[-1.1 isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if["" isnumber, yes, no]'}), 'no'); - }); - it('Properly evaluates !isnumber', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[1 !isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[.1 !isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1.1 !isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[-1 !isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[-.1 !isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[-1.1 !isnumber, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a !isnumber, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if["" !isnumber, yes, no]'}), 'yes'); - }); - it('Properly evaluates isnumber range', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[0 isnumber 1-3, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1 isnumber 1-3, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[2 isnumber 1-3, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[3 isnumber 1-3, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[4 isnumber 1-3, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[1.5 isnumber 1-2, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a isnumber 1-2, yes, no]'}), 'no'); - }); - it('Properly evaluates !isnumber range', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[0 !isnumber 1-3, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1 !isnumber 1-3, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[2 !isnumber 1-3, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[3 !isnumber 1-3, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[4 !isnumber 1-3, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[1.5 !isnumber 1-2, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a !isnumber 1-2, yes, no]'}), 'yes'); - }); - it('Properly evaluates regex', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[a regex /a/, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[A regex /a/i, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a regex /b/, yes, no]'}), 'no'); - }); - it('Properly evaluates !regex', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[a !regex /a/, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[A !regex /a/i, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a !regex /b/, yes, no]'}), 'yes'); - }); - it('Properly evaluates iswcm', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[a iswcm a, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[z iswcm a, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ab iswcm a?, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[bc iswcm a?, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[abc iswcm a?c, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ac iswcm a?c, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[a iswcm a*, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ab iswcm a*, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ab iswcm *b*, yes, no]'}), 'yes'); - }); - it('Properly evaluates !iswcm', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[a !iswcm a, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[z !iswcm a, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[ab !iswcm a?, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[bc !iswcm a?, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[abc !iswcm a?c, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ac !iswcm a?c, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[a !iswcm a*, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ab !iswcm a*, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[ab !iswcm *b*, yes, no]'}), 'no'); - }); - it('Properly evaluates iswcmcs', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[ab iswcmcs a?, yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[Ab iswcmcs a?, yes, no]'}), 'no'); - }); - it('Properly evaluates !iswcmcs', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[ab !iswcmcs a?, yes, no]'}), 'no'); - await expectEqual(() => evaluate({...options, expression: '$if[Ab !iswcmcs a?, yes, no]'}), 'yes'); - }); - }); - - describe('Input is $if with logical operator', function () { - it('Properly evaluates $ALL', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[$ALL[1 === 1], yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[$ALL[1 === 1, 2 === 2], yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[$ALL[1 === 1, 2 === 3], yes, no]'}), 'no'); - }); - it('Properly evaluates $ANY', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[$ANY[1 === 1], yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[$ANY[1 === 2, 2 === 2], yes, no]'}), 'yes'); - await expectEqual(() => evaluate({...options, expression: '$if[$ANY[1 === 2, 2 === 3], yes, no]'}), 'no'); - }); - it('Properly evaluates $NOT', async function () { - await expectEqual(() => evaluate({...options, expression: '$if[$NOT[1 === 1], yes, no]'}), 'no'); - }); - }); - - describe('Input all the things', function () { - it('Properly evaluates all the things', async function () { - const expression = `a \\b \\$ "c \\d \\"" $ten $sum[$ten, 1] $if[$NOT[$AND[1 === 1, $ten == 9]], 12, -1]\\` - const expect = `a \\b $ "c \\d "" 10 11 12\\` - await expectEqual(() => evaluate({...options, expression}), expect); - }); - }) -}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c948acb --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "ES2020", + + "module": "commonjs", + "esModuleInterop": true, + "lib": ["ES2020"], + "noImplicitAny": true, + + "rootDir": "src", + "baseUrl": ".", + "outDir": "lib", + + "incremental": true, + "tsBuildInfoFile": "lib/tsconfig.tsbuildinfo", + "declaration": true, + + "sourceMap": true, + + "preserveConstEnums": false, + + "newLine": "lf", + "removeComments": true + }, + "files":[ + "./src2/types/global.d.ts", + "./src/expressionish/index.ts" + ], + "exclude": [ + "node_modules/**/*" + ], +} \ No newline at end of file