diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f0140c4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules/ +/tmp +/src +/coverage +/tests +*.md +/.idea +/.git diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdfad22 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.{cmd,[cC}[mM][dD]} text eol=crlf +*.{bat,[bB}[aA][tT]} text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47c0519 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +/lib/ +/tmp/ +/dist/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..046f843 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ + +/compiler.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/jelly.iml b/.idea/jelly.iml new file mode 100644 index 0000000..7eaef70 --- /dev/null +++ b/.idea/jelly.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..d23208f --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..67fd72b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8dc4d77 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..f6c0580 --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +scope=@cs-au-dk +access=public +@cs-au-dk:registry=https://registry.npmjs.org/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..926decc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +FROM ubuntu:20.04 as builder +WORKDIR /tools + +# install Node +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + wget \ + netcat \ + ca-certificates && \ + apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* +ARG NODE_VERSION=18.12.1 +ARG NODE_PACKAGE=node-v${NODE_VERSION}-linux +RUN arch="$(dpkg --print-architecture)"; \ + case "$arch" in \ + amd64) export ARCH='x64' ;; \ + arm64) export ARCH='arm64' ;; \ + esac; \ + \ + wget -c https://nodejs.org/dist/v$NODE_VERSION/$NODE_PACKAGE-$ARCH.tar.gz -O -| tar -xzC /tools/ && \ + mv /tools/$NODE_PACKAGE-$ARCH /tools/node + +# install GraalVM JavaScript and NodeProf +RUN apt-get update && apt-get install -y git gcc g++ make python3 python3-pip && pip3 install ninja_syntax +RUN git clone --depth=1 --branch 6.0.4 https://github.com/graalvm/mx.git +RUN /tools/mx/mx fetch-jdk --java-distribution labsjdk-ce-17 +RUN mv /root/.mx/jdks/labsjdk-ce-17-* /tools/jdk +ENV JAVA_HOME=/tools/jdk +RUN git clone --depth=1 https://github.com/Haiyang-Sun/nodeprof.js.git +WORKDIR /tools/nodeprof.js +RUN /tools/mx/mx sforceimports +RUN /tools/mx/mx build +RUN /tools/mx/mx --dy /compiler build +ENV GRAAL_HOME=/tools/graal/sdk/latest_graalvm_home + +FROM ubuntu:20.04 +RUN mkdir -p /usr/lib/jvm +COPY --from=builder /tools/node /opt/node +COPY --from=builder /tools/jdk /usr/lib/jvm/jdk +COPY --from=builder /tools/graal/sdk/latest_graalvm_home /usr/lib/jvm/graalvm +ENV NODE_PATH /opt/node/lib/node_modules +ENV PATH /opt/node/bin:$PATH +ENV JAVA_HOME=/usr/lib/jvm/jdk +ENV GRAAL_HOME=/usr/lib/jvm/graalvm +ENV NODE_OPTIONS --max-old-space-size=8000 + +# install Jelly files built locally +RUN mkdir /jelly +WORKDIR /jelly +COPY ./package.json ./package-lock.json ./ +RUN npm install --omit=dev +COPY ./lib ./lib +RUN npm link +ENTRYPOINT ["node", "/jelly/lib/main.js"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cdb4bbf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Anders Møller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..864118f --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +# Jelly + +[![MIT License](https://img.shields.io/github/license/cs-au-dk/jelly)](LICENSE) +[![npm version](https://img.shields.io/npm/v/@cs-au-dk/jelly)](https://www.npmjs.com/package/@cs-au-dk/jelly) + +#### Copyright © 2023 Anders Møller + +Jelly is a static analyzer for performing + +* *call graphs construction*, +* *library usage pattern matching*, and +* *vulnerability exposure analysis* + +for JavaScript (and TypeScript) programs that use the Node.js platform. + +The analyzer design is based on ideas from JAM [1], TAPIR [2] and ACG [3]. +Its core is a flow-insensitive control-flow and points-to analysis that uses a hybrid of field-based and allocation-site abstraction, +together with access paths for tracking library usage. +It models the main parts of the ECMAScript language and standard library (intentionally not fully soundly!), +and not (yet) the Node.js standard library. + +[1] Benjamin Barslev Nielsen, Martin Toldam Torp, Anders Møller: +[Modular call graph construction for security scanning of Node.js applications](https://dl.acm.org/doi/10.1145/3460319.3464836). +ISSTA 2021: 29-41 + +[2] Anders Møller, Benjamin Barslev Nielsen, Martin Toldam Torp: +[Detecting locations in JavaScript programs affected by breaking library changes](https://dl.acm.org/doi/10.1145/3428255). +Proc. ACM Program. Lang. 4(OOPSLA): 187:1-187:25 (2020) + +[3] Asger Feldthaus, Max Schäfer, Manu Sridharan, Julian Dolby, Frank Tip: +[Efficient construction of approximate call graphs for JavaScript IDE services](https://ieeexplore.ieee.org/document/6606621/). ICSE 2013: 752-761 + +## Installing + +```bash +npm install -g @cs-au-dk/jelly +``` + +Other options are described below at [How to build](#how-to-build). + +## Usage + +See the full usage: +```bash +jelly --help +``` + +When running the Jelly static analyzer, one or more entry files are given as input. +Directories are expanded (using heuristics to skip certain files and directories, see [files.ts](src/misc/files.ts)). +All files reachable from entry files are analyzed, except +if option `--ignore-dependencies` is used, in which case only entry files are analyzed, +and only files within the base directory (auto-detected or specified using option `--basedir` or `-b`) are included. + +As an example, generate a call graph for the `winston` package and all its dependencies, both in JSON format and for HTML visualization: +```bash +jelly -j cg.json -m cg.html node_modules/winston -b node_modules +``` + +Viewing `cg.html` in a browser: + +![call graph visualization](misc/winston-cg.png) + +To set the heap limit, prefix commands by, for example: +```bash +NODE_OPTIONS=--max-old-space-size=4096 +``` + +Note that analyzing with all dependencies (i.e., not using `--ignore-dependencies`) can take a long time. +The options `--max-rounds` or `--timeout` can be used to terminate the analysis early to provide partial (unsound) results. + +## How to build + +Install dependencies: +```bash +npm install +``` + +Compile TypeScript code: +```bash +npm run build +``` + +After compilation, Jelly can be run like this: +```bash +node lib/main.js +``` + +Build binary executables (optional), placed in `dist/`: +```bash +sudo npm install -g pkg +npm run pkg +``` + +## Docker + +Build Docker image (including support for dynamic call graph construction): +```bash +npm run build-docker +``` + +Run Jelly in Docker with the directory specified as first argument as current working directory: +```bash +./bin/jelly-docker . tests/helloworld/app.js --callgraph-html cg.html +``` + +## Server-mode + +Jelly can be run in server-mode as an alternative to the command-line interface: +```bash +jelly-server +``` +or +```bash +node lib/server.js +``` +See also the instructions above for how to build binary executables. + +Requests to the server are sent on stdin using the JSON format described in `typings/ipc.d.ts`. +Responses are returned (asynchronously) on stdout with the two-line header (including the empty line) +``` +Content-Length: + +``` +with `\r\n` linebreaks. + +## Dynamic call graph construction + +Jelly supports dynamic call graph construction via [NodeProf](https://github.com/Haiyang-Sun/nodeprof.js/), +which can be used for measuring recall (or unsoundness) of the static analysis. + +Install NodeProf (see also the information about Docker above): +```bash +sudo dnf install g++ libstdc++-static +mkdir -p ~/tools; cd ~/tools +git clone --depth 1 --branch 6.0.4 https://github.com/graalvm/mx.git +export PATH=$PATH:$HOME/tools/mx +mx -y fetch-jdk --java-distribution labsjdk-ce-17 +export JAVA_HOME=$HOME/.mx/jdks/labsjdk-ce-17-jvmci-22.2-b01 +git clone --depth 1 https://github.com/Haiyang-Sun/nodeprof.js.git +cd nodeprof.js +mx sforceimports +mx --dy /compiler build +``` + +As an example, run `tests/micro/classes.js` or `tests/helloworld/app.js` with instrumentation for call graph construction: +```bash +export GRAAL_HOME=$HOME/tools/graal/sdk/latest_graalvm_home + +jelly tests/micro/classes.js -d cg.json +jelly tests/helloworld/app.js -d cg.json +``` +Extra arguments to the JavaScript program can be added after `--`. + +It is also possible to run `npm test` with instrumentation: +```bash +jelly --npm-test tests/mochatest -d cg.json +``` + +Another approach is to add `$JELLY_HOME/lib/bin/node` to `PATH` and set `JELLY_OUT`, for example to run Mocha directly: +```bash +cd tests/mochatest +PATH=$JELLY_HOME/lib/bin:$PATH JELLY_OUT=cg.json node_modules/.bin/mocha +``` +where `JELLY_HOME` is the home directory of Jelly. +This results in a file `cg.json-` for each instrumented file that is executed. + +Call graphs (generated either statically or dynamically) can be compared for precision and recall: +```bash +jelly --compare-callgraphs cg1.json cg2.json +``` + +## For developers + +Compile TypeScript code in watch mode: +```bash +npm run build-watch +``` + +Install as scripts (`jelly` and `jelly-server`) for development: +```bash +sudo npm link +``` + +Install dependencies for tests: +```bash +npm run tests-install +``` + +Run all tests: +```bash +npm test +``` + +Run individual tests (specified by regex), for example: +```bash +npm test -- -t tests/helloworld +``` + +### Differential testing + +Differential testing can be used to test if updated code results in lower recall than the previous version by comparing the dataflow graph and call graphs of the two versions. + +Run the following command to test the testing framework: +```bash +TAG= npm run differential -- -t tiny +``` +where `` is the git tag of the previous version you want to compare to. + +Then run the following commands to start full test: +```bash +TAG= npm run differential +``` + +During the test, the old version of Jelly will be installed in `tests/node_modules/jelly-previous` and test packages will be installed in `tmp/packages`. \ No newline at end of file diff --git a/bin/jelly-docker b/bin/jelly-docker new file mode 100755 index 0000000..3ddbebc --- /dev/null +++ b/bin/jelly-docker @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +if [[ -z "$1" ]]; then + echo "Error: Workspace root directory missing, aborting" + exit -1 +fi +docker run --rm --name jelly --network none -v $(readlink -f "$1"):/workspace -w /workspace --user $(id -u):$(id -g) jelly ${@:2} diff --git a/bin/node b/bin/node new file mode 100755 index 0000000..92f6f34 --- /dev/null +++ b/bin/node @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +export JELLY_BIN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +export JELLY_OUT=${JELLY_OUT:-'/tmp/jelly.json'} +DYNJS=$( dirname $JELLY_BIN )/dynamic/dyn.js + +if [[ -z "${GRAAL_HOME}" ]]; then + echo "Error: Environment variable GRAAL_HOME not set, aborting" + exit -1 +fi + +if [[ ! -x $GRAAL_HOME/bin/node ]]; then + echo "Error: $GRAAL_HOME/bin/node executable not found, aborting" + exit -1 +fi + +if [[ ! -f $GRAAL_HOME/tools/nodeprof/jalangi.js ]]; then + echo "Error: $GRAAL_HOME/tools/nodeprof/jalangi.js not found, aborting" + exit -1 +fi + +if [[ ! -f $DYNJS ]]; then + echo "Error: $DYNJS not found, aborting" + exit -1 +fi + +PATH=$GRAAL_HOME/bin:$PATH exec node --jvm --experimental-options --nodeprof $GRAAL_HOME/tools/nodeprof/jalangi.js --analysis $DYNJS $@ diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..7d5631b --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,211 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +const base = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest_rs", + + // Automatically clear mock calls, instances and results before every test + // clearMocks: false, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "tmp/coverage", + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + maxWorkers: 1, + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: "ts-jest", + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + roots: [ + "tests" + ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + "setupFilesAfterEnv": ["jest-expect-message"], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; + +export default { + projects: [ + { + displayName: "default", + ...base, + testMatch: [ + "**/*.test.ts" + ], + }, + { + displayName: "differential", + ...base, + // A path to a module which exports an async function that is triggered once before all test suites + globalSetup: "/tests/differential/install.ts", + // The glob patterns Jest uses to detect test files + testMatch: [ + "**/*.difftest.ts" + ], + transformIgnorePatterns: ["node_modules/(?!(jelly-previous)/)"] + }, + ], +} \ No newline at end of file diff --git a/misc/winston-cg.png b/misc/winston-cg.png new file mode 100644 index 0000000..803870f Binary files /dev/null and b/misc/winston-cg.png differ diff --git a/nodes.md b/nodes.md new file mode 100644 index 0000000..cf20412 --- /dev/null +++ b/nodes.md @@ -0,0 +1,294 @@ +# Babel AST node types + +https://babeljs.io/docs/en/babel-types +https://github.com/babel/babel/blob/master/packages/babel-parser/ast/spec.md + +### Program + +- [X] File (ignore) +- [X] Program + +### Declarations (excluding classes) + +- [X] VariableDeclaration + - [X] VariableDeclarator +- [X] FunctionDeclaration + +### Statements + +- [X] ReturnStatement +- [X] ThrowStatement +- [ ] CatchClause +- [X] DoWhileStatement (ignore) +- [X] EmptyStatement (ignore) +- [X] ContinueStatement (ignore) +- [X] ExpressionStatement (ignore) +- [X] SwitchStatement (ignore) + - [X] SwitchCase (ignore) +- [X] TryStatement (ignore) +- [X] WhileStatement (ignore) +- [X] BlockStatement (ignore) +- [X] BreakStatement (ignore) +- [X] IfStatement (ignore) +- [X] LabeledStatement (ignore) +- [X] ForStatement (ignore) +- [X] ForInStatement (ignore) +- [X] ForOfStatement +- [X] WithStatement (warn) + +### Literals + +- [X] StringLiteral +- [X] BooleanLiteral (ignore) +- [X] NullLiteral (ignore) +- [X] NumericLiteral (ignore) +- [X] BigIntLiteral (ignore) +- [X] RegExpLiteral (ignore) + +### Expressions (excluding literals, classes, etc.) + +- [X] Identifier +- [ ] PrivateName (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields) +- [X] ArrowFunctionExpression +- [X] AssignmentExpression +- [X] CallExpression +- [X] ConditionalExpression +- [X] FunctionExpression +- [X] LogicalExpression +- [X] MemberExpression +- [X] NewExpression +- [X] SequenceExpression +- [X] ObjectExpression (ignore) + - [X] ObjectMethod + - [X] ObjectProperty +- [X] ArrayExpression (ignore) +- [X] UnaryExpression (ignore) +- [X] BinaryExpression (ignore) +- [X] UpdateExpression (ignore) +- [X] ParenthesizedExpression (ignore) +- [X] TemplateLiteral (ignore) +- [X] TemplateElement (ignore) +- [X] OptionalCallExpression +- [X] OptionalMemberExpression +- [X] ThisExpression +- [X] YieldExpression +- [X] TaggedTemplateExpression +- [X] AwaitExpression + +### Classes + +- [X] ClassDeclaration +- [X] ClassExpression +- [X] ClassBody + - [X] ClassMethod + - [X] ClassPrivateMethod + - [X] ClassPrivateProperty + - [X] ClassProperty + - [X] StaticBlock +- [ ] Super (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) + +### Patterns, rest, spread + +- [X] AssignmentPattern +- [X] ObjectPattern +- [X] ArrayPattern +- [X] RestElement + + +- [ ] SpreadElement (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) + + +### Module/import/export + +- [X] ImportDeclaration + - [X] ImportSpecifier + - [X] ImportDefaultSpecifier + - [X] ImportNamespaceSpecifier + - [ ] ImportAttribute (https://github.com/tc39/proposal-import-assertions) +- [X] Import +- [X] ExportNamedDeclaration + - [X] ExportSpecifier + - [ ] ExportNamespaceSpecifier (`export * as x from "m"`, like `import * as x from "m"; export {x}`) + - [X] ExportDefaultSpecifier +- [X] ExportDefaultDeclaration +- [X] ExportAllDeclaration + +### Other + +- [X] Directive (ignore) + - [X] DirectiveLiteral (ignore) +- [X] Noop (ignore) +- [X] DebuggerStatement (ignore) +- [X] Placeholder (ignore) +- [X] InterpreterDirective (ignore) +- [X] V8IntrinsicIdentifier (see the 'v8intrinsic' Babel plugin) + +### JSX + +https://github.com/facebook/jsx/blob/main/AST.md + +- [X] JSXElement +- [X] JSXIdentifier +- [X] JSXMemberExpression +- [X] JSXFragment (ignore) +- [X] JSXNamespacedName (ignore) +- [X] JSXOpeningFragment (ignore) +- [X] JSXClosingFragment (ignore) +- [X] JSXExpressionContainer (ignore) +- [X] JSXEmptyExpression (ignore) +- [X] JSXSpreadChild (ignore) +- [X] JSXOpeningElement (ignore) +- [X] JSXClosingElement (ignore) +- [X] JSXAttribute (ignore) +- [X] JSXSpreadAttribute (ignore) +- [X] JSXText (ignore) + +# Language extensions (currently all ignored) + +### Module blocks + +https://github.com/tc39/proposal-js-module-blocks + +- ModuleExpression + +### Grouped accessors and auto-accessors + +https://github.com/tc39/proposal-grouped-and-auto-accessors + +- ClassAccessorProperty + +### Decimal + +https://github.com/tc39/proposal-decimal + +- DecimalLiteral + +### Generator function.sent meta property + +https://babeljs.io/docs/en/babel-plugin-proposal-function-sent + +- MetaProperty + +### Pipeline operator + +https://github.com/tc39/proposal-pipeline-operator +https://babeljs.io/docs/en/babel-plugin-proposal-pipeline-operator + +- PipelineBareFunction +- PipelineTopicExpression +- PipelinePrimaryTopicReference +- TopicReference + +### Decorators + +https://github.com/tc39/proposal-decorators +https://babeljs.io/docs/en/babel-plugin-proposal-decorators + +- Decorator + +### Records and tuples + +https://github.com/tc39/proposal-record-tuple +https://babeljs.io/docs/en/babel-plugin-proposal-record-and-tuple + +- RecordExpression +- TupleExpression + +### Do expressions + +https://github.com/tc39/proposal-do-expressions +https://babeljs.io/docs/en/babel-plugin-proposal-do-expressions + +- DoExpression + +### Partial application + +https://github.com/tc39/proposal-partial-application +https://babeljs.io/docs/en/babel-plugin-proposal-partial-application + +- ArgumentPlaceholder + +### Bind expressions + +https://github.com/tc39/proposal-bind-operator +https://babeljs.io/docs/en/babel-plugin-proposal-function-bind + +- BindExpression + +### TypeScript + +https://babeljs.io/docs/en/babel-types#typescript +https://babeljs.io/docs/en/babel-plugin-transform-typescript + +- TS* + +### Flow + +https://babeljs.io/docs/en/babel-types#flow +https://babeljs.io/docs/en/babel-plugin-transform-flow-strip-types + +- AnyTypeAnnotation +- ArrayTypeAnnotation +- BooleanLiteralTypeAnnotation +- BooleanTypeAnnotation +- ClassImplements +- DeclareClass +- DeclareExportAllDeclaration +- DeclareExportDeclaration +- DeclareFunction +- DeclareInterface +- DeclareModule +- DeclareModuleExport +- DeclareOpaqueType +- DeclareTypeAlias +- DeclareVariable +- DeclaredPredicate +- EmptyTypeAnnotation +- EnumBooleanBody +- EnumBooleanMember +- EnumDeclaration +- EnumDefaultedMember +- EnumNumberBody +- EnumNumberMember +- EnumStringBody +- EnumStringMember +- EnumSymbolBody +- ExistsTypeAnnotation +- FunctionTypeAnnotation +- FunctionTypeParam +- GenericTypeAnnotation +- IndexedAccessType +- InferredPredicate +- InterfaceDeclaration +- InterfaceExtends +- InterfaceTypeAnnotation +- IntersectionTypeAnnotation +- MixedTypeAnnotation +- NullLiteralTypeAnnotation +- NullableTypeAnnotation +- NumberLiteralTypeAnnotation +- NumberTypeAnnotation +- ObjectTypeAnnotation +- ObjectTypeCallProperty +- ObjectTypeIndexer +- ObjectTypeInternalSlot +- ObjectTypeProperty +- ObjectTypeSpreadProperty +- OpaqueType +- OptionalIndexedAccessType +- QualifiedTypeIdentifier +- StringLiteralTypeAnnotation +- StringTypeAnnotation +- SymbolTypeAnnotation +- TupleTypeAnnotation +- ThisTypeAnnotation +- TypeAlias +- TypeAnnotation +- TypeCastExpression +- TypeParameter +- TypeParameterDeclaration +- TypeParameterInstantiation +- TypeofTypeAnnotation +- UnionTypeAnnotation +- Variance +- VoidTypeAnnotation diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4513aad --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9521 @@ +{ + "name": "@cs-au-dk/jelly", + "version": "0.5.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@cs-au-dk/jelly", + "version": "0.5.0", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.12", + "@babel/parser": "^7.20.15", + "@babel/plugin-proposal-decorators": "^7.20.13", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typescript": "^7.20.13", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7", + "@types/semver": "^7.3.13", + "commander": "^9.4.1", + "micromatch": "^4.0.5", + "semver": "^7.3.8", + "stringify2stream": "^1.1.0", + "typescript": "^4.9.5", + "winston": "^3.7.2" + }, + "bin": { + "jelly": "lib/main.js", + "jelly-server": "lib/server.js" + }, + "devDependencies": { + "@types/babel__core": "^7.20.0", + "@types/babel__traverse": "^7.18.3", + "@types/jest": "^28.1.8", + "@types/micromatch": "^4.0.2", + "@types/node": "^18.13.0", + "jest": "^28.1.3", + "jest-expect-message": "^1.1.3", + "ts-jest": "^28.0.7", + "ts-node": "^10.9.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "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==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "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==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dependencies": { + "@babel/types": "^7.20.7", + "@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==", + "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-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "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==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "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==", + "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==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dependencies": { + "@babel/types": "^7.20.7" + }, + "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==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dependencies": { + "@babel/types": "^7.20.0" + }, + "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==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "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==", + "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==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + }, + "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==", + "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/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.13.tgz", + "integrity": "sha512-7T6BKHa9Cpd7lCueHBBzP0nkXNina+h5giOZw+a8ZpMfPFY19VjJAjIxyFHuWkhCWgL6QMqRiY/wB1fLXzm6Mw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.12", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/plugin-syntax-decorators": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-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-decorators": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", + "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-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.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.13.tgz", + "integrity": "sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.12", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-typescript": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@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.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "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/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "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/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": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/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/@jest/console/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/@jest/console/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/@jest/console/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/@jest/console/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/@jest/console/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/@jest/core": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.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": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/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/@jest/core/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/@jest/core/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/@jest/core/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/@jest/core/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/@jest/core/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/@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "dependencies": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "@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": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.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": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/transform/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/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "@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": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types/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/@jest/types/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/@jest/types/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/@jest/types/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/@jest/types/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/@jest/types/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/@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==", + "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==", + "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==", + "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==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.50", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.50.tgz", + "integrity": "sha512-k8ETQOOQDg5FtK7y9KJWpsGLik+QlPmIi8zzl/dGUgshV2QitprkFlCR/AemjWOTyKn9UwSSGRTzLVotvgCjYQ==", + "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/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@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.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/braces": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz", + "integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==", + "dev": true + }, + "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": "28.1.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", + "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", + "dev": true, + "dependencies": { + "expect": "^28.0.0", + "pretty-format": "^28.0.0" + } + }, + "node_modules/@types/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA==", + "dev": true, + "dependencies": { + "@types/braces": "*" + } + }, + "node_modules/@types/node": { + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" + }, + "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.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "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/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "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-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": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/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/babel-jest/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/babel-jest/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/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/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/babel-jest/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/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": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "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": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.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": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^28.1.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.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==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "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.30001449", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz", + "integrity": "sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "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==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "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.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", + "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": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/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": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "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==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "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==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": 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/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": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "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/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.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/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": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.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/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "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==", + "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/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.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/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==", + "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.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "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/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": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "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.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "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==", + "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": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "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.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "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-report/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/istanbul-lib-report/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/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": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", + "import-local": "^3.0.2", + "jest-cli": "^28.1.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.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": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/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/jest-circus/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/jest-circus/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/jest-circus/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/jest-circus/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/jest-circus/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/jest-cli": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/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/jest-cli/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/jest-cli/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/jest-cli/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/jest-cli/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/jest-cli/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/jest-config": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.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": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/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/jest-config/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/jest-config/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/jest-config/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/jest-config/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/jest-config/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/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/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/jest-each/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/jest-each/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/jest-each/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/jest-each/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/jest-each/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/jest-environment-node": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-expect-message": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.1.3.tgz", + "integrity": "sha512-bTK77T4P+zto+XepAX3low8XVQxDgaEqh3jSTQOG8qvPpD69LsIdyJTa+RmnJh3HNSzJng62/44RPPc7OIlFxg==", + "dev": true + }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.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": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-matcher-utils/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/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-message-util/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/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.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": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-resolve/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/jest-runner": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/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/jest-runner/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/jest-runner/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/jest-runner/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/jest-runner/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/jest-runner/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/jest-runtime": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-runtime/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/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.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": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-snapshot/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/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-util/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/jest-util/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/jest-util/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/jest-util/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/jest-util/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/jest-util/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/jest-validate": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/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/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-validate/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/jest-validate/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/jest-validate/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/jest-validate/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/jest-validate/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/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-watcher/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/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker/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/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==" + }, + "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/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "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/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "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/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "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/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/logform": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", + "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", + "dependencies": { + "@colors/colors": "1.5.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "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==", + "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/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "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.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-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.9", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.9.tgz", + "integrity": "sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA==" + }, + "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": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "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/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/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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "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/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.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/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/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/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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-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.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/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/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "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/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "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-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "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_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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/stringify2stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stringify2stream/-/stringify2stream-1.1.0.tgz", + "integrity": "sha512-69LPWdFoBFzPug93gJStxiBGaahUglPSomITXi9umiLhcyxEx1oyW27qcw5A7QVp9xwBygcAQJzkvoCZUSfrAw==" + }, + "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": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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-hyperlinks/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/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "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==", + "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==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/ts-jest": { + "version": "28.0.8", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", + "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.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": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^28.0.0", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "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.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/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "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/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "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/winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.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/wrap-ansi/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/wrap-ansi/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/wrap-ansi/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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/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==" + }, + "node_modules/yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.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/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "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==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==" + }, + "@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "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==" + } + } + }, + "@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "requires": { + "@babel/types": "^7.20.7", + "@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==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@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==" + }, + "@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==", + "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==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@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==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" + }, + "@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "requires": { + "@babel/types": "^7.20.0" + } + }, + "@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==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@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==" + }, + "@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==" + }, + "@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "requires": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==" + }, + "@babel/plugin-proposal-decorators": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.13.tgz", + "integrity": "sha512-7T6BKHa9Cpd7lCueHBBzP0nkXNina+h5giOZw+a8ZpMfPFY19VjJAjIxyFHuWkhCWgL6QMqRiY/wB1fLXzm6Mw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.20.12", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/plugin-syntax-decorators": "^7.19.0" + } + }, + "@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-decorators": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", + "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@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-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.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.13.tgz", + "integrity": "sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.20.12", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-typescript": "^7.20.0" + } + }, + "@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@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.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "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 + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@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" + } + }, + "@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": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "@jest/core": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "dev": true, + "requires": { + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.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": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + } + }, + "@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "requires": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + } + }, + "@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + } + }, + "@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "@jest/globals": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" + } + }, + "@jest/reporters": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "@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": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.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" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dev": true, + "requires": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "requires": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "@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==", + "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==" + }, + "@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==" + }, + "@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==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@sinclair/typebox": { + "version": "0.24.50", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.50.tgz", + "integrity": "sha512-k8ETQOOQDg5FtK7y9KJWpsGLik+QlPmIi8zzl/dGUgshV2QitprkFlCR/AemjWOTyKn9UwSSGRTzLVotvgCjYQ==", + "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" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@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.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/braces": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz", + "integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==", + "dev": true + }, + "@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": "28.1.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", + "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", + "dev": true, + "requires": { + "expect": "^28.0.0", + "pretty-format": "^28.0.0" + } + }, + "@types/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA==", + "dev": true, + "requires": { + "@types/braces": "*" + } + }, + "@types/node": { + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "dev": true + }, + "@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" + }, + "@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.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "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 + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "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" + } + }, + "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 + }, + "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==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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" + } + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "dev": true, + "requires": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "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": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "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": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^28.1.3", + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "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": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "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.30001449", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz", + "integrity": "sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", + "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": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "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": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.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==", + "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==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "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, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "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": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "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", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "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", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "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==" + }, + "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 + }, + "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": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "requires": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "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 + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "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==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "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, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "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 + }, + "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==" + }, + "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.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "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 + }, + "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", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "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.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "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 + }, + "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-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "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.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "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" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "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": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "dev": true, + "requires": { + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", + "import-local": "^3.0.2", + "jest-cli": "^28.1.3" + } + }, + "jest-changed-files": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-cli": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "dev": true, + "requires": { + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-config": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.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": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-environment-node": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "jest-expect-message": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.1.3.tgz", + "integrity": "sha512-bTK77T4P+zto+XepAX3low8XVQxDgaEqh3jSTQOG8qvPpD69LsIdyJTa+RmnJh3HNSzJng62/44RPPc7OIlFxg==", + "dev": true + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.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": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.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": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-resolve": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "dev": true, + "requires": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" + } + }, + "jest-runner": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "dev": true, + "requires": { + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-runtime": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.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": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-validate": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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 + }, + "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==" + }, + "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" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "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 + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "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 + }, + "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": "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": "^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 + }, + "logform": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", + "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", + "requires": { + "@colors/colors": "1.5.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "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==", + "requires": { + "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 + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "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.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-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.9", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.9.tgz", + "integrity": "sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA==" + }, + "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", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "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" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "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 + }, + "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", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "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 + }, + "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 + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "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" + } + }, + "pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "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 + } + } + }, + "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" + } + }, + "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 + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "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 + }, + "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" + } + }, + "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.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 + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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==" + }, + "safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==" + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "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 + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "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-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, + "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_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "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", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "stringify2stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stringify2stream/-/stringify2stream-1.1.0.tgz", + "integrity": "sha512-69LPWdFoBFzPug93gJStxiBGaahUglPSomITXi9umiLhcyxEx1oyW27qcw5A7QVp9xwBygcAQJzkvoCZUSfrAw==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "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==", + "requires": { + "has-flag": "^3.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" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "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-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "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==" + }, + "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==", + "requires": { + "is-number": "^7.0.0" + } + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "ts-jest": { + "version": "28.0.8", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", + "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.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.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 + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "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", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "requires": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "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", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "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 + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "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 + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a5e17e1 --- /dev/null +++ b/package.json @@ -0,0 +1,74 @@ +{ + "name": "@cs-au-dk/jelly", + "version": "0.5.0", + "description": "Jelly - call graph and library usage analyzer for JavaScript", + "author": "Anders Møller ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/cs-au-dk/jelly.git" + }, + "homepage": "https://github.com/cs-au-dk/jelly#readme", + "keywords": [ + "call graph", + "library usage", + "static analysis", + "program analysis" + ], + "files": [ + "lib" + ], + "bin": { + "jelly": "lib/main.js", + "jelly-server": "lib/server.js" + }, + "scripts": { + "build": "npm run copy-bin-resources; npm run chmod; tsc --build tsconfig-build.json", + "build-watch": "npm run copy-bin-resources; npm run chmod; tsc --build tsconfig-build.json -w", + "start": "node lib/main.js", + "copy-bin-resources": "mkdir -p lib; cp -r bin resources lib", + "chmod": "touch lib/main.js lib/server.js; chmod +x lib/main.js lib/server.js bin/node", + "tests-install": "tests/install.sh", + "test": "jest --selectProjects default", + "differential": "jest --selectProjects differential", + "pkg": "npm run clean; npm run build; pkg lib/main.js -C Brotli --options \"expose-gc,max-old-space-size=8192\" -c package.json --out-path dist; pkg lib/server.js -C Brotli --options \"expose-gc,max-old-space-size=8192\" -c package.json -o dist/jelly-server", + "clean": "rm -rf lib dist tmp/tsbuildinfo tmp/coverage tests/node_modules/jelly-previous", + "build-docker": "npm run build && docker build -t jelly .", + "jelly-docker": "./bin/jelly-docker" + }, + "dependencies": { + "@babel/core": "^7.20.12", + "@babel/parser": "^7.20.15", + "@babel/plugin-proposal-decorators": "^7.20.13", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typescript": "^7.20.13", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7", + "@types/semver": "^7.3.13", + "commander": "^9.4.1", + "micromatch": "^4.0.5", + "semver": "^7.3.8", + "stringify2stream": "^1.1.0", + "typescript": "^4.9.5", + "winston": "^3.7.2" + }, + "devDependencies": { + "@types/babel__core": "^7.20.0", + "@types/babel__traverse": "^7.18.3", + "@types/jest": "^28.1.8", + "@types/micromatch": "^4.0.2", + "@types/node": "^18.13.0", + "jest": "^28.1.3", + "jest-expect-message": "^1.1.3", + "ts-jest": "^28.0.7", + "ts-node": "^10.9.1" + }, + "pkg": { + "targets": [ + "node16-linux-x64", + "node16-macos-x64", + "node16-win-x64" + ], + "assets": "resources/**" + } +} diff --git a/resources/visualizer.html b/resources/visualizer.html new file mode 100644 index 0000000..89784e7 --- /dev/null +++ b/resources/visualizer.html @@ -0,0 +1,717 @@ + + + + Jelly + + + + + + + + + + + + + + + + +Jelly visualizer + + + +Collapse all +Collapse selected +Expand selected +Expand all packages +Expand all + + + +Remove selected +Remove non-selected + + + +Layout + + + + + Show call density + + Highlight reachable + + Hide unreachable + + + Show value density + + + + +Threshold: + + + + +Vulnerabilities: + + +Package dependency + +Module dependency + +Function reachability + + + + + + + + + diff --git a/src/analysis/accesspaths.ts b/src/analysis/accesspaths.ts new file mode 100644 index 0000000..7feb6c7 --- /dev/null +++ b/src/analysis/accesspaths.ts @@ -0,0 +1,97 @@ +import {DummyModuleInfo, ModuleInfo} from "./infos"; +import {ConstraintVar} from "./constraintvars"; + +/** + * Access paths used for describing package/module interfaces. + */ +export abstract class AccessPath { + + private readonly str: string; + + protected constructor(str: string) { + this.str = str; + } + + toString(): string { + return this.str; + } +} + +/** + * Access path that represents module.exports values (for exports interfaces) or require("...") values (for imports interfaces). + */ +export class ModuleAccessPath extends AccessPath { + + readonly moduleInfo: ModuleInfo | DummyModuleInfo; + + readonly requireName: string | undefined; + + constructor(moduleInfo: ModuleInfo | DummyModuleInfo, requireName: string) { + const t = !"./#".includes(requireName[0]) && requireName !== moduleInfo.getOfficialName() ? requireName : undefined; // only use require name if not relative and different from official name + super(`<${moduleInfo.getOfficialName()}${t ? `(${t})` : ""}>`); + this.moduleInfo = moduleInfo; + this.requireName = t; + } +} + +/** + * Access path that represents an object property. + */ +export class PropertyAccessPath extends AccessPath { + + readonly base: ConstraintVar; + + readonly prop: string; + + constructor(base: ConstraintVar, prop: string) { + super(`${base}.${prop}`); + this.base = base; + this.prop = prop; + } +} + +/** + * Access path that represents the result of a function call (possibly with 'new'). + */ +export class CallResultAccessPath extends AccessPath { + + readonly caller: ConstraintVar; + + constructor(caller: ConstraintVar) { + super(`${caller}()`); + this.caller = caller; + } +} + +/** + * Access path that represents the result of a JSX component instantiation. + */ +export class ComponentAccessPath extends AccessPath { + + readonly component: ConstraintVar; + + constructor(component: ConstraintVar) { + super(`${component}<>`); + this.component = component; + } +} + +/** + * Access path that represents values from ignored modules. + */ +export class IgnoredAccessPath extends AccessPath { + + constructor() { + super("Ignored"); + } +} + +/** + * Access path that represents unknown values. + */ +export class UnknownAccessPath extends AccessPath { + + constructor() { + super("Unknown"); + } +} diff --git a/src/analysis/analysisstate.ts b/src/analysis/analysisstate.ts new file mode 100644 index 0000000..d34c5b5 --- /dev/null +++ b/src/analysis/analysisstate.ts @@ -0,0 +1,686 @@ +import { + CallExpression, + Class, + Function, + identifier, + Identifier, + isArrowFunctionExpression, + isExpression, + isNode, + NewExpression, + Node, + OptionalCallExpression, + SourceLocation +} from "@babel/types"; +import { + FilePath, + getOrSet, + mapGetSet, + sourceLocationToString, + sourceLocationToStringWithFile, + sourceLocationToStringWithFileAndEnd, + SourceLocationWithFilename, + strHash +} from "../misc/util"; +import {ConstraintVar, NodeVar} from "./constraintvars"; +import logger from "../misc/logger"; +import {ObjectToken, PackageObjectToken, Token} from "./tokens"; +import {dirname, relative, resolve} from "path"; +import {NodePath} from "@babel/traverse"; +import assert from "assert"; +import {getPackageJsonInfo, PackageJsonInfo} from "../misc/packagejson"; +import {DummyModuleInfo, FunctionInfo, ModuleInfo, PackageInfo} from "./infos"; +import {options} from "../options"; +import { + AccessPath, + CallResultAccessPath, + ComponentAccessPath, + ModuleAccessPath, + PropertyAccessPath +} from "./accesspaths"; +import {ConstraintVarProducer} from "./constraintvarproducer"; +import Timer from "../misc/timer"; +import {VulnerabilityDetector} from "../patternmatching/vulnerabilitydetector"; + +export const globalLoc: SourceLocation = {start: {line: 0, column: 0}, end: {line: 0, column: 0}}; + +export const undefinedIdentifier = identifier("undefined"); // TODO: prevent writes to 'undefined'? +undefinedIdentifier.loc = globalLoc; + +export class AnalysisState { // TODO: move some of these fields to FragmentState? + + /** + * Map from constraint variable string hash to canonical ConstraintVar object. + */ + readonly canonicalConstraintVars: Map = new Map; + + /** + * Map from AST node to canonical NodeVar object. + */ + readonly canonicalNodeVars: Map = new Map; + + /** + * Map from token string hash to canonical Token object. + */ + readonly canonicalTokens: Map = new Map; + + /** + * Map from access path string hash to canonical AccessPath object. + */ + readonly canonicalAccessPaths: Map = new Map; + + /** + * Map that provides for each function/module the set of modules being required. + */ + readonly requireGraph: Map> = new Map; + + /** + * Map that provides for each function/module the set of functions that may be called. + */ + readonly functionToFunction: Map> = new Map; + + /** + * Map that provides for each call site location the set of functions that may be called. (For output only.) + */ + readonly callToFunction: Map> = new Map; // TODO: redundant? see callToFunctionOrModule + + /** + * Map from call/require/import node to functions/modules that may be called/imported. + */ + readonly callToFunctionOrModule: Map> = new Map; + + readonly callToContainingFunction: Map = new Map; + + /** + * Map from require/import call to the set of modules being required. (For output only.) + */ + readonly callToModule: Map> = new Map; // TODO: redundant? see callToFunctionOrModule + + /** + * Total number of function->function call graph edges. (For statistics only.) + */ + numberOfFunctionToFunctionEdges: number = 0; + + /** + * Total number of call->function call graph edges. (For statistics only.) + */ + numberOfCallToFunctionEdges: number = 0; + + /** + * Map from "name@version" to package info, "" is used for entry files if no package.json is found. + */ + readonly packageInfos: Map = new Map; + + /** + * Map from normalized module path to ModuleInfo. + * Note: different paths may refer to the same ModuleInfo! (if they belong to the same package and version) + */ + readonly moduleInfos: Map = new Map; + + /** + * Set of DummyModuleInfos created (for module files that haven't been found). + */ + readonly dummyModuleInfos: Map = new Map; + + /** + * Map from Function AST object to FunctionInfo. + */ + readonly functionInfos: Map = new Map; + + /** + * Functions that use 'arguments'. + */ + readonly functionsWithArguments: Set = new Set; + + /** + * Functions that use 'this'. + */ + readonly functionsWithThis: Set = new Set; + + /** + * Source code locations that correspond to the start of artificial functions in dyn.ts. + * Such functions are ignored during soundness testing. + */ + readonly artificialFunctions: Array<[ModuleInfo, Node]> = []; + + /** + * Call nodes for each module. (Only used with options.callgraphJson.) + */ + readonly calls: Map> = new Map; + + /** + * Source locations of all calls (including accessor calls). + */ + readonly callLocations: Set = new Set; + + /** + * Source locations of calls to/from known native functions. + */ + readonly nativeCallLocations: Set = new Set; + + /** + * Source locations of calls to external functions. + */ + readonly externalCallLocations: Set = new Set; + + /** + * Calls with unused result. + * Used by PatternMatcher. + */ + readonly callsWithUnusedResult: Set = new Set; + + /** + * Calls where the result may be used as a promise. + * Used by PatternMatcher. + */ + readonly callsWithResultMaybeUsedAsPromise: Set = new Set; + + /** + * Constraint variables that represent function parameters. + */ + readonly functionParameters: Map> = new Map; + + /** + * Expressions that are invoked at calls. + * Used by PatternMatcher. + */ + readonly invokedExpressions: Set = new Set; + + /** + * Constraint variables that represent expressions whose values may escape to other modules. + * Includes arguments to functions from other modules. + */ + readonly maybeEscaping: Set = new Set; + + /** + * Object tokens that have been widened. + */ + readonly widened: Set = new Set; + + /** + * Unhandled dynamic property write operations. + */ + readonly unhandledDynamicPropertyWrites: Map = new Map; + + /** + * Unhandled dynamic property read operations. + */ + readonly unhandledDynamicPropertyReads: Set = new Set; + + /** + * Number of errors. (For statistics only.) + */ + errors: number = 0; + + /** + * Number of warnings. (For statistics only.) + */ + warnings: number = 0; + + /** + * AST nodes where a warning has been emitted. + */ + readonly nodesWithWarning: WeakSet = new WeakSet; + + /** + * Entry files. + */ + readonly entryFiles: Set = new Set; + + /** + * Files reached during analysis. + */ + readonly reachedFiles: Set = new Set; + + /** + * Files reached and waiting to be analyzed. + */ + readonly pendingFiles: Array = []; + + /** + * Files that could not be parsed. + */ + readonly filesWithParseErrors: Array = []; + + /** + * Files that have been analyzed (without parse error). + */ + readonly filesAnalyzed: Array = []; + + /** + * 'require' expressions and import/export declarations/expressions where ModuleAccessPaths are created. + * Used by PatternMatcher. + */ + readonly moduleAccessPaths: Map> = new Map; + + /** + * Property read expressions where PropertyAccessPaths are created. + * ap |-> prop |-> n |-> {bp, sub} means that ap appears at the base sub-expression of the property read expression n with + * property prop, bp is the access path for n, and sub is the constraint variable of the sub-expression. + * Used by PatternMatcher. + */ + readonly propertyReadAccessPaths: Map>> = new Map; + + /** + * Property write expressions where PropertyAccessPaths are created. + * ap |-> prop |-> n |-> {bp, sub} means that ap appears at the base sub-expression of the property write expression n with + * property prop, bp is the access path for n, and sub is the constraint variable of the sub-expression. + * Used by PatternMatcher. + */ + readonly propertyWriteAccessPaths: Map>> = new Map; + + /** + * Expressions and associated CallResultAccessPaths where CallResultAccessPaths are created. + * ap |-> n |-> {bp, sub} means that ap appears at the function sub-expression of the call expression n, + * bp is the access path for n, and sub is the constraint variable of the sub-expression. + * Used by PatternMatcher. + */ + readonly callResultAccessPaths: Map> = new Map; + + /** + * Expressions and associated ComponentAccessPaths where ComponentAccessPaths are created. + * ap |-> n |-> {bp, sub} means that ap appears at the function sub-expression of the component creation expression n, + * bp is the access path for n, and sub is the constraint variable of the sub-expression. + * Used by PatternMatcher. + */ + readonly componentAccessPaths: Map> = new Map; + + /** + * Map from identifier declarations at imports to uses. + * Used by PatternMatcher. + */ + readonly importDeclRefs: Map> = new Map; + + /** + * Constraint variable producer. + */ + readonly varProducer = new ConstraintVarProducer(this); + + /** + * Timeout timer. + */ + readonly timeoutTimer = new Timer; + + /** + * Cache of PackageJsonInfos. + */ + readonly packageJsonInfos = new Map(); + + /** + * Property reads that may have empty result. + */ + maybeEmptyPropertyReads: Array<{result: ConstraintVar, base: ConstraintVar, pck: PackageObjectToken}> = []; + + /** + * Dynamic property writes. + */ + dynamicPropertyWrites = new Set(); + + /** + * Number of calls to canonicalizeVar. + */ + numberOfCanonicalizeVarCalls = 0; + + /** + * Number of calls to canonicalizeToken. + */ + numberOfCanonicalizeTokenCalls = 0; + + /** + * Number of calls to canonicalizeAccessPath. + */ + numberOfCanonicalizeAccessPathCalls = 0; + + /** + * Dynamic analysis time. + */ + dynamicAnalysisTime: number = 0; + + /** + * Vulnerability information, only used if options.vulnerabilities is set. + */ + vulnerabilities: VulnerabilityDetector | undefined; + + /** + * Returns the canonical representative of the given constraint variable (possibly the given one). + */ + canonicalizeVar(v: T): T { + this.numberOfCanonicalizeVarCalls++; + if (v instanceof NodeVar) + return getOrSet(this.canonicalNodeVars, v.node, () => v) as unknown as T; + else + return getOrSet(this.canonicalConstraintVars, strHash(v.toString()), () => v) as T; + } + + /** + * Returns the canonical representative of the given token (possibly the given one). + */ + canonicalizeToken(t: T): T { + this.numberOfCanonicalizeTokenCalls++; + return getOrSet(this.canonicalTokens, strHash(t.toString()), () => t) as T; + } + + /** + * Returns the canonical representative of the given access path (possibly the given one). + */ + canonicalizeAccessPath(t: T): T { + this.numberOfCanonicalizeAccessPathCalls++; + return getOrSet(this.canonicalAccessPaths, strHash(t.toString()), () => t) as T; + } + + /** + * Adds an edge in the call graph (both function->function and call->function). + */ + registerCallEdge(call: Node, from: FunctionInfo | ModuleInfo, to: FunctionInfo, + {native, accessor, external}: {native?: boolean, accessor?: boolean, external?: boolean} = {}) { + if ((!accessor || options.callgraphImplicit) && + (!native || options.callgraphNative) && + (!external || options.callgraphExternal)) { + // register function->function + let fs = mapGetSet(this.functionToFunction, from); + if (!fs.has(to)) + this.numberOfFunctionToFunctionEdges++; + fs.add(to); + // register call->function + let cs = mapGetSet(this.callToFunction, call); + if (!cs.has(to)) { + this.numberOfCallToFunctionEdges++; + if (logger.isVerboseEnabled()) + logger.verbose(`Adding call edge from call ${sourceLocationToStringWithFileAndEnd(call.loc)}, function ${from} -> ${to}`); + } + cs.add(to); + } + // register call->function/module + mapGetSet(this.callToFunctionOrModule, call).add(to); + this.callToContainingFunction.set(call, from); + } + + /** + * Registers a call location. + */ + registerCall(n: Node, m: ModuleInfo, {native, external, accessor}: {native?: boolean, external?: boolean, accessor?: boolean} = {}) { + if (accessor && !options.callgraphImplicit) + return; + if (options.callgraphJson) + mapGetSet(this.calls, m).add(n); + if (!this.callLocations.has(n) || + (native && !this.nativeCallLocations.has(n)) || + (external && !this.externalCallLocations.has(n))) { + if (logger.isDebugEnabled()) + logger.debug(`Adding ${native ? "native " : external ? "external " : accessor ? "accessor " : ""}call ${sourceLocationToStringWithFileAndEnd(n.loc!)}`); + this.callLocations.add(n); + if (native) + this.nativeCallLocations.add(n); + else if (external) + this.externalCallLocations.add(n); + } + } + + /** + * Registers a require/import call. + */ + registerRequireCall(node: Node, from: ModuleInfo | FunctionInfo, m: ModuleInfo | DummyModuleInfo) { + if (options.callgraphRequire) + mapGetSet(this.callToModule, node).add(m); + mapGetSet(this.callToFunctionOrModule, node).add(m); + this.callToContainingFunction.set(node, from); + } + + /** + * Registers a call node whose result is unused. + */ + registerCallWithUnusedResult(n: CallExpression | OptionalCallExpression | NewExpression) { + this.callsWithUnusedResult.add(n); + } + + /** + * Registers a call node whose result may be used as a promise. + */ + registerCallWithResultMaybeUsedAsPromise(n: CallExpression | OptionalCallExpression | NewExpression) { + this.callsWithResultMaybeUsedAsPromise.add(n); + } + + /** + * Registers a constraint variable that represents a function parameter. + */ + registerFunctionParameter(v: ConstraintVar, fun: Function) { + mapGetSet(this.functionParameters, fun).add(v); + } + + /** + * Registers that values of the expression represented by the given constraint variable may escape to other modules. + */ + registerEscaping(v: ConstraintVar | undefined) { + if (v) + this.maybeEscaping.add(v); + } + + /** + * Registers a call to another module. + */ + registerEscapingArguments(args: CallExpression["arguments"], path: NodePath) { + for (const arg of args) + if (isExpression(arg)) // TODO: handle non-Expression arguments? + this.registerEscaping(this.varProducer.expVar(arg, path)); + } + + /** + * Registers an expression that is invoked at a call. + */ + registerInvokedExpression(n: Node) { + this.invokedExpressions.add(n); + } + + /** + * Registers a function that may be ignored in output from dyn.ts. + */ + registerArtificialFunction(m: ModuleInfo, n: Node) { + this.artificialFunctions.push([m, n]); + } + + /** + * Registers an unhandled dynamic property write operation. + */ + registerUnhandledDynamicPropertyWrite(node: Node, src: ConstraintVar, source: string | undefined) { + this.unhandledDynamicPropertyWrites.set(node, {src, source}); + } + + /** + * Registers an unhandled dynamic property read operation. + */ + registerUnhandledDynamicPropertyRead(node: Node) { + this.unhandledDynamicPropertyReads.add(node); + } + + /** + * Emits an error message. + */ + error(msg: string) { + logger.error(`Error: ${msg}`); + this.errors++; + } + + /** + * Emits a warning message. + */ + warn(msg: string) { + logger.warn(`Warning: ${msg}`); + this.warnings++; + } + + /** + * Emits a warning message about an unsupported language feature or library function. + * If avoidDuplicates is set, at most one warning is generated per node. + */ + warnUnsupported(node: Node, msg: string = node.type, avoidDuplicates: boolean = false) { + if (avoidDuplicates) { + if (this.nodesWithWarning.has(node)) + return; + this.nodesWithWarning.add(node); + } + if (options.warningsUnsupported) + this.warn(`${msg} at ${sourceLocationToStringWithFile(node.loc)}`); + else + this.warnings++; + } + + /** + * Returns the ModuleInfo of the given module. + */ + getModuleInfo(file: FilePath): ModuleInfo { + const m = this.moduleInfos.get(file); + if (!m) + assert.fail(`ModuleInfo for ${file} not found`); + return m; + } + + /** + * Registers a new FunctionInfo for a function/method/constructor. + */ + registerFunctionInfo(file: FilePath, path: NodePath, name: string | undefined, fun: Function, loc: SourceLocation | null | undefined) { + const m = this.moduleInfos.get(file)!; + const f = new FunctionInfo(name, loc, m); + this.functionInfos.set(fun, f); + const parent = path.getFunctionParent()?.node; + (parent ? this.functionInfos.get(parent)!.functions : m.functions).set(fun, f); + if (this.vulnerabilities) + this.vulnerabilities.reachedFunction(path, f); + } + + /** + * Registers that the current function uses 'arguments'. + * Returns the enclosing (non-arrow) function, or undefined if no such function. + */ + registerArguments(path: NodePath): Function | undefined { + let p: NodePath | NodePath | null | undefined = path, f: Function | undefined; + do { + f = (p = p?.getFunctionParent())?.node; + } while (f && isArrowFunctionExpression(f)); + if (f) { + this.functionsWithArguments.add(f); + if (logger.isDebugEnabled()) + logger.debug(`Function uses 'arguments': ${sourceLocationToStringWithFile(f.loc)}`); + } + return f; + } + + /** + * Registers that the current function uses 'this'. + */ + registerThis(path: NodePath): Function | undefined { + let p: NodePath | NodePath | null | undefined = path, f: Function | undefined; + do { + f = (p = p?.getFunctionParent())?.node; + } while (f && isArrowFunctionExpression(f)); + if (f) { + this.functionsWithThis.add(f); + if (logger.isDebugEnabled()) + logger.debug(`Function uses 'this': ${sourceLocationToStringWithFile(f.loc)}`); + } + return f; + } + + /** + * Finds the nearest enclosing function or module. + */ + getEnclosingFunctionOrModule(path: NodePath, moduleInfo: ModuleInfo): FunctionInfo | ModuleInfo { + const p = path.getFunctionParent()?.node; + const caller = p ? this.functionInfos.get(p)! : moduleInfo; + if (!caller) + assert.fail(`Function/module info not found at ${moduleInfo}:${sourceLocationToString(path.node.loc)}!?!`); + return caller; + } + + /** + * Records that the given file has been reached, and returns its ModuleInfo. + */ + reachedFile(tofile: FilePath, from?: Function | FilePath): ModuleInfo { + let moduleInfo; + if (this.reachedFiles.has(tofile)) + moduleInfo = this.moduleInfos.get(tofile)!; + else { + + // find package.json and extract name, version, and main file + const p = getOrSet(this.packageJsonInfos, dirname(tofile), () => getPackageJsonInfo(tofile)); + const rel = relative(p.dir, tofile); + + // find or create PackageInfo + let packageInfo = this.packageInfos.get(p.packagekey); + let otherfile: string | undefined; + if (!packageInfo) { + + // package has not been reached before (also not in another directory) + packageInfo = new PackageInfo(p.name, p.version, p.main, p.dir, from === undefined); + this.packageInfos.set(p.packagekey, packageInfo); + if (!options.modulesOnly && options.printProgress && logger.isVerboseEnabled()) + logger.verbose(`Reached package ${packageInfo} at ${p.dir}`); + if (this.vulnerabilities) + this.vulnerabilities.reachedPackage(packageInfo); + + } else { + + // package has been reached before, but maybe in another directory, so look for ModuleInfo there + otherfile = resolve(packageInfo.dir, rel); + moduleInfo = this.moduleInfos.get(otherfile); + } + + if (moduleInfo) { + + // modules has been reached before in another directory + if (logger.isVerboseEnabled()) + logger.verbose(`${moduleInfo} already encountered in another directory`); + } else { + + // module has not been reached before, create new ModuleInfo + moduleInfo = new ModuleInfo(rel, packageInfo, tofile, from === undefined); + packageInfo.modules.set(rel, moduleInfo); + + // record that module has been reached + this.reachedFiles.add(tofile); + if (from && options.ignoreDependencies) + logger.info(`Ignoring module ${moduleInfo}`); + else + this.pendingFiles.push(tofile); + if (this.vulnerabilities) + this.vulnerabilities.reachedModule(moduleInfo); + + // if the package was reached before in another directory, record the ModuleInfo for the file in that directory + if (otherfile) + this.moduleInfos.set(otherfile, moduleInfo); + } + + // record the ModuleInfo for the given file + this.moduleInfos.set(tofile, moduleInfo); + } + + // unless this is an entry file... + if (from) { + + // extend the require graph + const fr = typeof from === "string" ? this.moduleInfos.get(from)! : this.functionInfos.get(from)!; + const to = this.moduleInfos.get(tofile)!; + mapGetSet(this.requireGraph, fr).add(to); + + // extend the package dependencies and dependents + const pf = fr.packageInfo; + const pt = to.packageInfo; + if (pf !== pt && !pf.directDependencies.has(pt)) { + pf.directDependencies.add(pt); + if (logger.isVerboseEnabled()) + logger.verbose(`Package ${pf} depends on ${pt}`); + } + } + return moduleInfo; + } + + /** + * Finds the module or package that the given constraint variable belongs to, + * returns undefined for constraint variables that do not belong to a specific package. + */ + getConstraintVarParent(v: ConstraintVar): PackageInfo | ModuleInfo | undefined { + const p = v.getParent(); + if (isNode(p) || (p && "loc" in p && p.loc)) + return this.moduleInfos.get((p.loc as SourceLocationWithFilename).filename)!; + return undefined; + } +} diff --git a/src/analysis/analyzer.ts b/src/analysis/analyzer.ts new file mode 100644 index 0000000..2a2b39e --- /dev/null +++ b/src/analysis/analyzer.ts @@ -0,0 +1,320 @@ +import fs from "fs"; +import {resolve} from "path"; +import logger, {writeStdOutIfActive} from "../misc/logger"; +import Solver, {AbortedException} from "./solver"; +import Timer, {TimeoutException} from "../misc/timer"; +import {addAll, FilePath, mapMapSize, percent} from "../misc/util"; +import {visit} from "./astvisitor"; +import {PackageInfo} from "./infos"; +import {options, resolveBaseDir} from "../options"; +import assert from "assert"; +import {getComponents, nuutila} from "../misc/scc"; +import {widenObjects} from "./widening"; +import {findModules} from "./modulefinder"; +import {parseAndDesugar} from "../parsing/parser"; +import {findEscapingObjects} from "./escaping"; +import {buildNatives} from "../natives/nativebuilder"; +import {AnalysisStateReporter} from "../output/analysisstatereporter"; +import {Operations} from "./operations"; +import {Program} from "@babel/types"; +import {UnknownAccessPath} from "./accesspaths"; +import {Token} from "./tokens"; + +export async function analyzeFiles(files: Array, solver: Solver, returnFileMap: boolean = false): Promise> { + const a = solver.analysisState; + const timer = new Timer(); + resolveBaseDir(); + const fileMap = new Map(); + try { + if (files.length === 0) + logger.info("Error: No files to analyze"); + else { + + // resolve entry files relative to basedir + for (const file of files) + a.entryFiles.add(resolve(options.basedir, file)); // TODO: optionally resolve using require.resolve instead? + + // analyze files reachable from the entry files top-down + for (const file of a.entryFiles) + a.reachedFile(file); + while (a.pendingFiles.length > 0) { + const file = a.pendingFiles.shift()!; + const moduleInfo = a.getModuleInfo(file); + + solver.diagnostics.modules++; + if (!options.modulesOnly && options.printProgress) + logger.info(`Analyzing module ${file} (${solver.diagnostics.modules})`); + + writeStdOutIfActive(`Parsing ${file}...`); + const str = fs.readFileSync(file, "utf8"); // TODO: OK to assume utf8? (ECMAScript says utf16??) + solver.diagnostics.codeSize += str.length; + const ast = parseAndDesugar(str, file, a); + if (!ast) { + a.filesWithParseErrors.push(file); + continue; + } + if (returnFileMap) + fileMap.set(file, {sourceCode: str, program: ast.program}) + + if (options.modulesOnly) { + + // find modules only, no actual analysis + findModules(ast, file, solver); + + } else { + + // initialize analysis state for the module + solver.prepare(); + + // prepare model of native library + const [globals, specials] = buildNatives(solver, moduleInfo); + + // traverse the AST + writeStdOutIfActive("Traversing AST..."); + visit(ast, new Operations(file, solver, globals, specials)); + + // propagate tokens until fixpoint reached for the module + await solver.propagate(); + + // find escaping objects and add UnknownAccessPaths + const escaping = findEscapingObjects(moduleInfo, solver); + + // if enabled, widen escaping objects for this module + if (options.alloc && options.widening) + widenObjects(moduleInfo, escaping, solver); + + // propagate tokens (again) until fixpoint reached + await solver.propagate(); + + // store the analysis state for the module + solver.store(moduleInfo); + + a.filesAnalyzed.push(file); + solver.updateDiagnostics(); + } + } + + if (!options.modulesOnly) { + + if (!options.bottomUp) { + + // combine analysis states for all modules + solver.prepare(); + const totalNumPackages = Array.from(a.packageInfos.values()).reduce((acc, p) => + acc + (Array.from(p.modules.values()).some(m => m.fragmentState) ? 1 : 0), 0); + for (const p of a.packageInfos.values()) { + await solver.checkAbort(); + + // skip the package if it doesn't contain any modules that have been analyzed + if (!Array.from(p.modules.values()).some(m => m.fragmentState)) + continue; + + solver.diagnostics.packages++; + if (options.printProgress) + logger.info(`Analyzing package ${p} (${solver.diagnostics.packages}/${totalNumPackages})`); + + // restore analysis state for each module + for (const m of p.modules.values()) + solver.restore(m); + + // connect neighbors + for (const d of p.directDependencies) + solver.addPackageNeighbor(p, d); + } + + // propagate tokens until fixpoint reached + await solver.propagate(); + + await patchDynamics(solver); + + } else { + + // compute strongly connected components from the package dependency graph + if (logger.isVerboseEnabled()) + for (const p of a.packageInfos.values()) { + logger.verbose(`Package ${p} dependencies:${p.directDependencies.size === 0 ? " -" : ""}`); + for (const d of p.directDependencies) + logger.verbose(` ${d}`); + } + const components = getComponents(nuutila(a.packageInfos.values(), (p: PackageInfo) => p.directDependencies)); + + // combine local analysis results bottom-up in the package structure + const transdeps = new Map>(); // direct and transitive dependencies in other components + const totalNumPackages = components.reduce((acc, scc) => + acc + scc.reduce((acc, p) => + acc + (Array.from(p.modules.values()).some(m => m.fragmentState) ? 1 : 0), 0), 0); + for (const scc of components) { + + // skip the component if it doesn't contain any modules that have been analyzed + if (!(Array.from(scc).some(p => Array.from(p.modules.values()).some(m => m.fragmentState)))) + continue; + + solver.diagnostics.packages += scc.length; + if (options.printProgress) + if (scc.length === 1) + logger.info(`Analyzing package ${scc[0]} (${solver.diagnostics.packages}/${totalNumPackages})`); + else + logger.info(`Analyzing mutually dependent packages ${scc.join(", ")}`); + + // compute solution for the strongly connected component + solver.prepare(); + const deps = new Set(); // direct dependencies in other components + const trans = new Set(); // transitive dependencies in other components + for (const p of scc) { + + // restore the tokens of the modules of the packages in the component + for (const m of p.modules.values()) + solver.restore(m); + + // collect dependencies in other components + const pd = new Set(); + for (const d of p.directDependencies) + if (!scc.includes(d)) { + pd.add(d); + const td = transdeps.get(d); + if (td) + for (const dd of td) { + pd.add(dd); + trans.add(dd); + } + } + transdeps.set(p, pd); + + // collect direct dependencies in other components and connect neighbors + for (const d of p.directDependencies) { + if (!scc.includes(d)) + deps.add(d); + solver.addPackageNeighbor(p, d); + } + } + // restore tokens from the direct dependencies in other components + for (const d of deps) + if (!trans.has(d)) // transitive dependencies can safely be skipped + solver.restore(d); + + // propagate tokens until fixpoint reached for the scc packages with their dependencies + await solver.propagate(); + + await patchDynamics(solver); + + // store the tokens for the packages in the component + for (const p of scc) + solver.store(p); + // TODO: persist package(/module?) tokens, seed when analyzing the package/module again (note: modules are only analyzed when reached) + + assert(a.pendingFiles.length === 0, "Unexpected module"); // (new modules shouldn't be discovered in the bottom-up phase) + } + + // restore all tokens (safe to restore for one package of each component and to skip the last component) + let lastComponent = true; + for (const scc of components.reverse()) { + if (lastComponent) { + lastComponent = false; + continue; + } + solver.restore(scc[0], false); + } + } + + solver.updateDiagnostics(); + } + } + + } catch (ex) { + solver.updateDiagnostics(); + if (ex instanceof TimeoutException) { + solver.diagnostics.timeout = true; + } else if (ex instanceof AbortedException) { + solver.diagnostics.aborted = true; + } else + throw ex; + } + solver.diagnostics.time = timer.elapsed(); + solver.diagnostics.cpuTime = timer.elapsedCPU(); + if (solver.diagnostics.aborted) + logger.warn("Received abort signal, analysis aborted"); + else if (solver.diagnostics.timeout) + logger.warn("Time limit reached, analysis aborted"); + + // output statistics + if (!options.modulesOnly && logger.isInfoEnabled() && files.length > 0) { + const f = solver.fragmentState; // current fragment (not final if aborted due to timeout) + const r = new AnalysisStateReporter(a, f); + if (options.warningsUnsupported && !solver.diagnostics.aborted && !solver.diagnostics.timeout) { + r.reportNonemptyUnhandledDynamicPropertyWrites(); + r.reportNonemptyUnhandledDynamicPropertyReads(); + } + logger.info(`Analyzed packages: ${solver.diagnostics.packages}, modules: ${solver.diagnostics.modules}, functions: ${a.functionInfos.size}, code size: ${Math.round(solver.diagnostics.codeSize / 1024)}KB`); + const one = r.getOneCalleeCalls(), zero = r.getZeroCalleeCalls().size, native = r.getZeroButNativeCalleeCalls(), external = r.getZeroButExternalCalleeCalls(), nativeOrExternal = r.getZeroButNativeOrExternalCalleeCalls(), all = a.callLocations.size; + logger.info(`Call edges function->function: ${a.numberOfFunctionToFunctionEdges}, call->function: ${a.numberOfCallToFunctionEdges}`); + logger.info(`Calls with unique callee: ${one}/${all - zero - native - external - nativeOrExternal}${all - zero - native - external - nativeOrExternal > 0 ? ` (${percent(one / (all - zero - native - external - nativeOrExternal))})` : ""}` + + ` (excluding ${zero} zero-callee, ${native} native-only, ${external} external-only and ${nativeOrExternal} native-or-external-only)`) + logger.info(`Functions with zero callers: ${r.getZeroCallerFunctions().size}/${a.functionInfos.size}`); + logger.info(`Analysis time: ${solver.diagnostics.time}ms, memory usage: ${solver.diagnostics.maxMemoryUsage}MB${!options.gc ? " (without --gc)" : ""}`); + logger.info(`Analysis errors: ${a.errors}, warnings: ${a.warnings}${a.warnings > 0 && !options.warningsUnsupported ? " (show with --warnings-unsupported)" : ""}`); + if (options.diagnostics) { + logger.info(`Iterations: ${solver.diagnostics.iterations}, listener notification rounds: ${solver.listenerNotificationRounds}`); + if (options.maxRounds !== undefined) + logger.info(`Fixpoint round limit reached: ${solver.roundLimitReached} time${solver.roundLimitReached !== 1 ? "s" : ""}`); + logger.info(`Constraint vars: ${f.getNumberOfVarsWithTokens()} (${f.vars.size}), tokens: ${f.numberOfTokens}, subset edges: ${f.numberOfSubsetEdges}, max tokens: ${solver.largestTokenSetSize}, max subset out: ${solver.largestSubsetEdgeOutDegree}`); + logger.info(`Listeners (notifications) normal: ${mapMapSize(f.tokenListeners)} (${solver.tokenListenerNotifications}), ` + + `pair: ${mapMapSize(f.pairListeners1) + mapMapSize(f.pairListeners2)} (${solver.pairListenerNotifications}), ` + + `neighbor: ${mapMapSize(f.packageNeighborListeners)} (${solver.packageNeighborListenerNotifications}), ` + + `inheritance: ${mapMapSize(f.ancestorListeners)} (${solver.ancestorListenerNotifications}), ` + + `array: ${mapMapSize(f.arrayEntriesListeners)} (${solver.arrayEntriesListenerNotifications}), ` + + `obj: ${mapMapSize(f.objectPropertiesListeners)} (${solver.objectPropertiesListenerNotifications})`); + logger.info(`Canonicalize vars: ${a.canonicalConstraintVars.size} (${a.numberOfCanonicalizeVarCalls}), tokens: ${a.canonicalTokens.size} (${a.numberOfCanonicalizeTokenCalls}), access paths: ${a.canonicalAccessPaths.size} (${a.numberOfCanonicalizeAccessPathCalls})`); + logger.info(`CPU time: ${solver.diagnostics.cpuTime}ms, propagation: ${solver.totalPropagationTime}ms, listeners: ${solver.totalListenerCallTime}` + + `ms${options.alloc && options.widening ? `, widening: ${solver.totalWideningTime}ms` : ""}`); + if (options.cycleElimination) + logger.info(`Cycle elimination time: ${solver.totalCycleEliminationTime}ms, runs: ${solver.totalCycleEliminationRuns}, nodes removed: ${f.redirections.size}`); + } + } + + return fileMap; +} + +/** + * Patches empty object property constraint variables that may be affected by dynamic property writes. + */ +async function patchDynamics(solver: Solver) { + if (!options.patchDynamics) + return; + const a = solver.analysisState; + const f = solver.fragmentState; + const dyns = new Set(); + for (const v of a.dynamicPropertyWrites) + addAll(f.getTokens(f.getRepresentative(v)), dyns); + // constraint: for all E.p (or E[..]) where ⟦E.p⟧ (or ⟦E[..]⟧) is empty and ⟦E⟧ contains a token that is base of a dynamic property write + let count = 0; + const r: typeof a.maybeEmptyPropertyReads = []; + for (const e of a.maybeEmptyPropertyReads) { + const {result, base, pck} = e; + const bs = f.getTokens(f.getRepresentative(base)); + const [size] = f.getTokensSize(f.getRepresentative(result)); + if (size === 0) { + let dpw = false; + for (const t of bs) + if (dyns.has(t)) { + dpw = true; // base has a token that is base of a dynamic property write + break; + } + if (dpw) { + if (logger.isDebugEnabled()) + logger.debug(`Empty object property read ${result} with dynamic write to base object ${base}`); + + // constraint: ...: @Unknown ∈ ⟦E⟧ and k ∈ ⟦E.p⟧ (or ⟦E[..]⟧) where k is the package containing the property read operation + solver.addAccessPath(a.canonicalizeAccessPath(new UnknownAccessPath()), base); + solver.addTokenConstraint(pck, result); // TODO: omit? + count++; + } else + r.push(e); // keep only the property reads that are still empty + } + } + a.maybeEmptyPropertyReads = r; + if (count > 0) { + if (logger.isVerboseEnabled()) + logger.verbose(`${count} empty object property read${count === 1 ? "" : "s"} patched, propagating again`); + await solver.propagate(); + } +} diff --git a/src/analysis/astvisitor.ts b/src/analysis/astvisitor.ts new file mode 100644 index 0000000..bef987e --- /dev/null +++ b/src/analysis/astvisitor.ts @@ -0,0 +1,790 @@ +import traverse, {NodePath} from "@babel/traverse"; +import { + ArrayExpression, + ArrowFunctionExpression, + AssignmentExpression, + AssignmentPattern, + AwaitExpression, + CallExpression, + ClassAccessorProperty, + ClassDeclaration, + ClassExpression, + ClassMethod, + ClassPrivateMethod, + ClassPrivateProperty, + ClassProperty, + ConditionalExpression, + ExportAllDeclaration, + ExportDefaultDeclaration, + ExportNamedDeclaration, + File, + ForOfStatement, + Function, + FunctionDeclaration, + FunctionExpression, + Identifier, + ImportDeclaration, + isArrayPattern, + isArrowFunctionExpression, + isAssignmentExpression, + isAssignmentPattern, + isClassAccessorProperty, + isClassExpression, + isClassMethod, + isClassPrivateMethod, + isClassPrivateProperty, + isClassProperty, + isDeclaration, + isExportDeclaration, + isExportDefaultDeclaration, + isExportDefaultSpecifier, + isExportNamedDeclaration, + isExpression, + isFunctionDeclaration, + isFunctionExpression, + isIdentifier, + isImportDefaultSpecifier, + isImportSpecifier, + isLVal, + isObjectMethod, + isObjectPattern, + isObjectProperty, + isPattern, + isRestElement, + isSpreadElement, + JSXElement, + JSXMemberExpression, + LogicalExpression, + LVal, + MemberExpression, + NewExpression, + ObjectExpression, + ObjectMethod, + ObjectProperty, + OptionalCallExpression, + OptionalMemberExpression, + Program, + RegExpLiteral, + ReturnStatement, + SequenceExpression, + StaticBlock, + Super, + TaggedTemplateExpression, + ThisExpression, + ThrowStatement, + variableDeclaration, + variableDeclarator, + VariableDeclarator, + WithStatement, + YieldExpression +} from "@babel/types"; +import { + AccessPathToken, + AllocationSiteToken, + ClassToken, + FunctionToken, + NativeObjectToken, + ObjectToken, + PackageObjectToken, + Token +} from "./tokens"; +import {ModuleInfo} from "./infos"; +import logger from "../misc/logger"; +import {mapArrayAdd, sourceLocationToStringWithFile, SourceLocationWithFilename} from "../misc/util"; +import assert from "assert"; +import {globalLoc, undefinedIdentifier} from "./analysisstate"; +import {options} from "../options"; +import {ComponentAccessPath, PropertyAccessPath} from "./accesspaths"; +import {ConstraintVar} from "./constraintvars"; +import { + getBaseAndProperty, + getClass, + getExportName, + getImportName, + getKey, + getProperty, + isParentExpressionStatement +} from "../misc/asthelpers"; +import { + ASYNC_GENERATOR_PROTOTYPE_NEXT, + GENERATOR_PROTOTYPE_NEXT, + PROMISE_FULFILLED_VALUES +} from "../natives/ecmascript"; +import {Operations} from "./operations"; +import {TokenListener} from "./listeners"; + +export const IDENTIFIER_KIND = Symbol(); + +export function visit(ast: File, op: Operations) { + const solver = op.solver; + const a = solver.analysisState; + let nextNodeIndex = 1; + + a.maybeEscaping.clear(); // TODO: move to method in AnalysisState? + + // traverse the AST and extend the analysis result with information about the current module + if (logger.isVerboseEnabled()) + logger.verbose(`Traversing AST of ${op.file}`); + traverse(ast, { + + enter(path: NodePath) { + + // workaround to ensure that AST nodes with undefined location (caused by desugaring) can be identified uniquely + if (!path.node.loc) { + let p: NodePath | null = path; + while (p && !p.node.loc) + p = p.parentPath; + path.node.loc = {filename: op.file, start: p?.node.loc?.start, end: p?.node.loc?.end, nodeIndex: nextNodeIndex++} as any; // see sourceLocationToString + } + }, + + Program(path: NodePath) { + + // set module source location + op.moduleInfo.loc = path.node.loc; + + // artificially declare all globals in the program scope (if not already declared) + const decls = [...op.globals, undefinedIdentifier] // TODO: treat 'undefined' like other globals? + .filter(d => path.scope.getBinding(d.name) === undefined) + .map(id => { + const d = variableDeclarator(id); + d.loc = globalLoc; + return d; + }); + const d = variableDeclaration("var", decls); + d.loc = globalLoc; + path.scope.registerDeclaration(path.unshiftContainer("body", d)[0]); + }, + + ThisExpression(path: NodePath) { + + // this + a.registerThis(path); + + // constraint: t ∈ ⟦this⟧ where t denotes the package + solver.addTokenConstraint(op.packageObjectToken, a.varProducer.nodeVar(path.node)); + + const fun = path.getFunctionParent(); + if (fun) { + + // constraint: ⟦this_f⟧ ⊆ ⟦this⟧ where f is the enclosing function + solver.addSubsetConstraint(a.varProducer.thisVar(fun.node), a.varProducer.nodeVar(path.node)); + } else { + + // constraint %globalThis ∈ ⟦this⟧ + solver.addTokenConstraint(op.natives.get("globalThis")!, a.varProducer.nodeVar(path.node)); + } + + // constraint: @Unknown ∈ ⟦this⟧ + solver.addAccessPath(op.theUnknownAccessPath, a.varProducer.nodeVar(path.node)); // TODO: omit this constraint in certain situations? + }, + + Identifier(path: NodePath) { + if (path.node.name === "arguments") // registers use of 'arguments' + a.varProducer.identVar(path.node, path); // FIXME: registerArguments may be called too late if the function is recursive + + if (options.variableKinds) { + const binding = path.scope.getBinding(path.node.name); + if (binding) + (binding.identifier as any)[IDENTIFIER_KIND] = binding.kind; + } + }, + + MemberExpression: { // TODO: actually more efficient to visit nodes bottom-up? (if not, most rules don't need to use 'exit') + exit(path: NodePath) { + visitMemberExpression(path); + } + }, + + OptionalMemberExpression: { + exit(path: NodePath) { + visitMemberExpression(path); + } + }, + + JSXMemberExpression: { + exit(path: NodePath) { + visitMemberExpression(path); + } + }, + + ReturnStatement: { + exit(path: NodePath) { + if (path.node.argument) { + const fun = path.getFunctionParent(); + if (fun) { + const expVar = op.expVar(path.node.argument, path); + + // return E + let resVar; + if (fun.node.generator) { + // find the iterator object (it is returned via Function) + // constraint: ... ⊆ ⟦i.value⟧ where i is the iterator object for the function + const iter = a.canonicalizeToken(new AllocationSiteToken("Iterator", fun.node.body, op.packageInfo)); + resVar = a.varProducer.objPropVar(iter, "value"); + } else { + // constraint: ... ⊆ ⟦ret_f⟧ where f is the enclosing function (ignoring top-level returns) + resVar = a.varProducer.returnVar(fun.node); + } + + if (fun.node.async && !fun.node.generator) { + // make a new promise with the fulfilled value being the return value + const promise = op.newPromiseToken(fun.node); + solver.addSubsetConstraint(expVar, a.varProducer.objPropVar(promise, PROMISE_FULFILLED_VALUES)); + solver.addTokenConstraint(promise!, resVar); + } else + solver.addSubsetConstraint(expVar, resVar); + } + } + } + }, + + Function(path: NodePath) { // FunctionDeclaration | FunctionExpression | ObjectMethod | ArrowFunctionExpression | ClassMethod | ClassPrivateMethod + // record that a function/method/constructor/getter/setter has been reached, connect to its enclosing function or module + const fun = path.node; + let cls; + if (isClassMethod(fun) && fun.kind === "constructor") + cls = getClass(path); + const name = isFunctionDeclaration(path.node) || isFunctionExpression(path.node) ? path.node.id?.name : + (isObjectMethod(path.node) || isClassMethod(path.node)) ? getKey(path.node) : + cls ? cls.id?.name : undefined;// for constructors, use the class name if present + const anon = isFunctionDeclaration(path.node) || isFunctionExpression(path.node) ? path.node.id === null : isArrowFunctionExpression(path.node); + const loc = cls ? cls.loc : // for constructors, use the class location (workaround to match dyn.ts) + isClassMethod(fun) && fun.static ? {filename: (fun.key.loc as SourceLocationWithFilename).filename, start: fun.key.loc!.start, end: fun.loc!.end} : // for static methods, use the identifier location (workaround to match dyn.ts) + fun.loc; + const msg = cls ? "constructor" : `${name ?? (anon ? "" : "")}`; + if (logger.isVerboseEnabled()) + logger.verbose(`Reached function ${msg} at ${sourceLocationToStringWithFile(loc)}`); + a.registerFunctionInfo(op.file, path, name, fun, loc); + if (!name && !anon) + a.warnUnsupported(fun, `Computed ${isFunctionDeclaration(path.node) || isFunctionExpression(path.node) ? "function" : "method"} name`); // TODO: handle functions/methods with unknown name? + + if (fun.generator) { + + // function* + + // constraint: %(Async)Generator.prototype.next ⊆ ⟦i.next⟧ where i is the iterator object for the function + const iter = a.canonicalizeToken(new AllocationSiteToken("Iterator", fun.body, op.packageInfo)); + const iterNext = a.varProducer.objPropVar(iter, "next"); + solver.addTokenConstraint(op.natives.get(fun.async ? ASYNC_GENERATOR_PROTOTYPE_NEXT : GENERATOR_PROTOTYPE_NEXT)!, iterNext); + + // constraint i ∈ ⟦ret_f⟧ where i is the iterator object for the function + solver.addTokenConstraint(iter, a.varProducer.returnVar(fun)); + } + }, + + FunctionDeclaration: { + exit(path: NodePath) { + + // function f(...) {...} (as declaration) + // constraint: t ∈ ⟦f⟧ where t denotes the function + const to = path.node.id ? path.node.id : path.node; // export default functions may not have names, use the FunctionDeclaration node as constraint variable in that situation + solver.addTokenConstraint(op.newFunctionToken(path.node), a.varProducer.nodeVar(to)); + } + }, + + FunctionExpression: { + exit(path: NodePath) { + + // function f(...) {...} (as expression, possibly without name) + // constraint: t ∈ ⟦function f(...) {...}⟧ where t denotes the function + if (!isParentExpressionStatement(path)) + solver.addTokenConstraint(op.newFunctionToken(path.node), a.varProducer.nodeVar(path.node)); + // constraint: t ∈ ⟦f⟧ (if the function is named) where t denotes the function + if (path.node.id) + solver.addTokenConstraint(op.newFunctionToken(path.node), a.varProducer.nodeVar(path.node.id)); + } + }, + + ArrowFunctionExpression: { + exit(path: NodePath) { + + // (...) => E + // constraint: t ∈ ⟦(...) => E⟧ where t denotes the function + if (!isParentExpressionStatement(path)) + solver.addTokenConstraint(op.newFunctionToken(path.node), a.varProducer.nodeVar(path.node)); + // constraint: ⟦E⟧ ⊆ ⟦ret_f⟧ where f is the function + if (isExpression(path.node.body)) + solver.addSubsetConstraint(op.expVar(path.node.body, path), a.varProducer.returnVar(path.node)); + } + }, + + CallExpression: { + exit(path: NodePath) { + + // E0(E1,...) + visitCallOrNew(false, path); + } + }, + + OptionalCallExpression: { + exit(path: NodePath) { + + // E?.E0(E1,...) + visitCallOrNew(false, path); + } + }, + + NewExpression: { + exit(path: NodePath) { + + // new E0(E1,...) + visitCallOrNew(true, path); + } + }, + + AssignmentExpression: { + exit(path: NodePath) { + const oper = path.node.operator; + if (oper === '=' || oper === '||=' || oper === '&&=' || oper === '??=') { + const eVar = op.expVar(path.node.right, path); + op.assign(eVar, path.node.left, path.node, a.getEnclosingFunctionOrModule(path, op.moduleInfo), path, false); + + // constraint: ⟦E⟧ ⊆ ⟦... = E⟧ + if (!isParentExpressionStatement(path)) + solver.addSubsetConstraint(eVar, a.varProducer.nodeVar(path.node)); + } + } + }, + + AssignmentPattern: { + exit(path: NodePath) { + + // X = E (as default value) + // constraint: ⟦E⟧ ⊆ ⟦X⟧ (if X is a simple identifier...) + op.assign(op.expVar(path.node.right, path), path.node.left, path.node, a.getEnclosingFunctionOrModule(path, op.moduleInfo), path, false); + } + }, + + VariableDeclarator: { // handles VariableDeclaration + exit(path: NodePath) { + if (path.node.init) { + + // var/let/const X = E + // constraint: ⟦E⟧ ⊆ ⟦X⟧ (if X is a simple identifier...) + op.assign(op.expVar(path.node.init, path), path.node.id, path.node, a.getEnclosingFunctionOrModule(path, op.moduleInfo), path, false); + } + } + }, + + ConditionalExpression: { + exit(path: NodePath) { + + // E1 ? E2 : E3 + // constraints: ⟦E2⟧ ⊆ ⟦E1 ? E2 : E3⟧, ⟦E3⟧ ⊆ ⟦E1 ? E2 : E3⟧ + if (!isParentExpressionStatement(path)) { + solver.addSubsetConstraint(op.expVar(path.node.consequent, path), a.varProducer.nodeVar(path.node)); + solver.addSubsetConstraint(op.expVar(path.node.alternate, path), a.varProducer.nodeVar(path.node)); + } + } + }, + + LogicalExpression: { + exit(path: NodePath) { + + // E1 op E2 where op is ||, && or ?? + // constraints: ⟦E1⟧ ⊆ ⟦E1 op E2⟧, ⟦E2⟧ ⊆ ⟦E1 op E2⟧ + // (the former can safely be omitted for && when only tracking functions and objects) + if (!isParentExpressionStatement(path)) { + if (path.node.operator !== "&&") + solver.addSubsetConstraint(op.expVar(path.node.left, path), a.varProducer.nodeVar(path.node)); + solver.addSubsetConstraint(op.expVar(path.node.right, path), a.varProducer.nodeVar(path.node)); + } + } + }, + + SequenceExpression: { + exit(path: NodePath) { // TODO: handle in expVar (like ParenthesizedExpression) to reduce size of constraint graph? + + // (..., ..., E) + // constraint: ⟦E⟧ ⊆ ⟦(..., ..., E)⟧ + if (!isParentExpressionStatement(path)) + solver.addSubsetConstraint(op.expVar(path.node.expressions[path.node.expressions.length - 1], path), a.varProducer.nodeVar(path.node)); + } + }, + + Property: { // ObjectProperty | ClassProperty | ClassAccessorProperty | ClassPrivateProperty + exit(path: NodePath) { + if (isPattern(path.parent)) + return; // pattern properties are handled at assign + if (isClassAccessorProperty(path.node)) + assert.fail(`Encountered ClassAccessorProperty at ${sourceLocationToStringWithFile(path.node.loc)}`); // https://github.com/tc39/proposal-grouped-and-auto-accessors + const key = getKey(path.node); + if (key) { + if (path.node.value) { + if (!isExpression(path.node.value)) + assert.fail(`Unexpected Property value type ${path.node.value?.type} at ${sourceLocationToStringWithFile(path.node.loc)}`); + + // {..., p: E, ...} or class... {...; p = E; ...} (static or non-static, private or public) + const rightvar = op.expVar(path.node.value, path); + let dst; + if (options.alloc && isObjectProperty(path.node)) { + // constraint: ⟦E⟧ ⊆ ⟦i.p⟧ where i is the object literal + dst = a.varProducer.objPropVar(a.canonicalizeToken(new ObjectToken(path.parentPath.node, op.packageInfo)), key); + } else if (options.alloc && (isClassProperty(path.node) || isClassAccessorProperty(path.node) || isClassPrivateProperty(path.node)) && path.node.static) { + // constraint: ⟦E⟧ ⊆ ⟦c.p⟧ where c is the class + const cls = getClass(path); + assert(cls); + dst = a.varProducer.objPropVar(a.canonicalizeToken(new ClassToken(cls, op.packageInfo)), key); + } else { + // constraint: ⟦E⟧ ⊆ ⟦k.p⟧ where k is the current package + dst = a.varProducer.packagePropVar(op.file, key); + } + solver.addSubsetConstraint(rightvar, dst); + // TODO: special treatment for ClassPrivateProperty? static properties? + } + } else + a.warnUnsupported(path.node, "Computed property name"); // TODO: nontrivial computed property name + if (isClassProperty(path.node)) // dyn.ts treats class property initializers as functions + a.registerArtificialFunction(op.moduleInfo, path.node.key); + } + }, + + Method: { // ObjectMethod | ClassMethod | ClassPrivateMethod + exit(path: NodePath) { + switch (path.node.kind) { + case "method": + case "get": + case "set": + const key = getKey(path.node); + if (key) { + + // [class C...] {... p(..) {...} ...} (static or non-static, private or public) + const t = op.newFunctionToken(path.node); + const ac = path.node.kind === "method" ? "normal" : path.node.kind; + let dst; + if (options.alloc && isObjectMethod(path.node)) { + // constraint: t ∈ ⟦(ac)i.p⟧ where t denotes the function, i is the object literal, + // and (ac) specifies whether it is a getter, setter or normal property + dst = a.varProducer.objPropVar(a.canonicalizeToken(new ObjectToken(path.parentPath.node, op.packageInfo)), key, ac); + } else if (options.alloc && (isClassMethod(path.node) || isClassPrivateMethod(path.node)) && path.node.static) { + // constraint: t ∈ ⟦(ac)c.p⟧ where t denotes the function, c is the class, + // and (ac) specifies whether it is a getter, setter or normal property + const cls = getClass(path); + assert(cls); + dst = a.varProducer.objPropVar(a.canonicalizeToken(new ClassToken(cls, op.packageInfo)), key, ac); + + } else { + // constraint: t ∈ ⟦(ac)k.p⟧ where t denotes the function and k is the current package, + // and (ac) specifies whether it is a getter, setter or normal property + dst = a.varProducer.packagePropVar(op.file, key, ac); + } + solver.addTokenConstraint(t, dst); + // TODO: special treatment for ClassPrivateMethod? static properties? + } else + a.warnUnsupported(path.node, "Computed method name"); // TODO: nontrivial computed method name + break; + case "constructor": + + // class C... {... constructor(..) {...} ...} + // constraint: t ∈ ⟦C⟧ where t denotes the constructor function + const cls = getClass(path); + if (cls && cls.id) // note: to match dyn.ts, the FunctionToken uses the actual constructor location, but the FunctionInfo uses the location of the class + solver.addTokenConstraint(op.newFunctionToken(path.node), a.varProducer.nodeVar(cls.id)); + break; + } + // TODO: currently ignoring generator, async, static (often easy to resolve!), override, optional, abstract + } + }, + + Class: { // ClassExpression | ClassDeclaration + exit(path: NodePath) { + + if (path.node.superClass) { + + // class C extends E {...} + // constraint: ⟦E⟧ ⊆ ⟦extends_c⟧ where c is the class + solver.addSubsetConstraint(op.expVar(path.node.superClass, path), a.varProducer.extendsVar(path.node)); // TODO: test class inheritance (see C11 in classes.js) + } + + let constructor: ClassMethod | ClassPrivateMethod | undefined; + for (const b of path.node.body.body) + if ((isClassMethod(b) || isClassPrivateMethod(b)) && b.kind === "constructor") + constructor = b; + const exported = isExportDeclaration(path.parent); + if (constructor) { + if (isClassExpression(path.node) || exported) { + + // class ... {...} + // constraint: t ∈ ⟦class ... {...}⟧ where t denotes the constructor function + if (!isParentExpressionStatement(path) || exported) + solver.addTokenConstraint(op.newFunctionToken(constructor), a.varProducer.nodeVar(path.node)); + } + } else // no explicit constructor (dyn.ts records a call to an implicit constructor) + a.registerArtificialFunction(op.moduleInfo, path.node); + + // class ... {...} + // constraint: c ∈ ⟦class ... {...}⟧ where c is the ClassToken + const ct = op.newClassToken(path.node); + if (isClassExpression(path.node) || exported) + solver.addTokenConstraint(ct, a.varProducer.nodeVar(path.node)); + + // constraint: c ∈ ⟦C⟧ where c is the ClassToken + if (path.node.id) + solver.addTokenConstraint(ct, a.varProducer.nodeVar(path.node.id)); + } + }, + + ObjectExpression(path: NodePath) { + + // {...} + if (!isParentExpressionStatement(path)) { + + // constraint: t ∈ ⟦{...}⟧ where t is the object for this allocation site + solver.addTokenConstraint(op.newObjectToken(path.node), a.varProducer.nodeVar(path.node)); + // TODO: fall back to field-based if an object token appears in a constraint variable together with >k other object tokens? (see analysisstate.add) + + for (const p of path.node.properties) + if (isSpreadElement(p)) { + a.warnUnsupported(p, "SpreadElement in ObjectExpression"); // TODO: SpreadElement in ObjectExpression + } // (ObjectProperty and ObjectMethod are handled at rules Property and Method respectively) + } + }, + + ArrayExpression(path: NodePath) { + + // [...] + if (!isParentExpressionStatement(path)) { + + // constraint: t ∈ ⟦{...}⟧ where t is the array for this allocation site + const t = op.newArrayToken(path.node); + solver.addTokenConstraint(t, a.varProducer.nodeVar(path.node)); + + for (const [index, e] of path.node.elements.entries()) + if (isExpression(e)) { + + // constraint: ⟦E⟧ ⊆ ⟦t.i⟧ for each array element E with index i + const prop = String(index); + solver.addSubsetConstraint(op.expVar(e, path), a.varProducer.objPropVar(t, prop)); + } else if (e) + a.warnUnsupported(e, "SpreadElement in ArrayExpression"); // TODO: SpreadElement in ArrayExpression + } + }, + + StaticBlock(path: NodePath) { + a.registerArtificialFunction(op.moduleInfo, path.node); // dyn.ts treats static blocks as functions + }, + + ThrowStatement: { + exit(path: NodePath) { + a.registerEscaping(op.expVar(path.node.argument, path)); + } + }, + + CatchClause: { + // TODO: CatchClause + }, + + Super(path: NodePath) { + a.warnUnsupported(path.node); // TODO: super + }, + + ImportDeclaration(path: NodePath) { + + // model 'import' like 'require' + op.requireModule(path.node.source.value, a.varProducer.nodeVar(path.node), path); // TODO: see TODO in requireResolve about using import.meta.resolve + + let any = false; + for (const imp of path.node.specifiers) { + switch (imp.type) { + case "ImportNamespaceSpecifier": + + // bind the module export object to the namespace identifier + solver.addSubsetConstraint(a.varProducer.nodeVar(path.node), a.varProducer.nodeVar(imp.local)); + break; + + case "ImportSpecifier": + case "ImportDefaultSpecifier": + any = true; + break; + } + // record identifier uses for pattern matcher + const refs = path.scope.getBinding(imp.local.name)?.referencePaths; + if (refs) + for (const ref of refs) + mapArrayAdd(imp.local, ref.node, a.importDeclRefs); + } + // bind each module export object property to the local identifier + if (any) { + + // constraint: ∀ objects t ∈ ⟦import...⟧: ⟦t.p⟧ ⊆ ⟦x⟧ where p is the property and x is the local identifier + // for each import specifier + solver.addForAllConstraint(a.varProducer.nodeVar(path.node), TokenListener.IMPORT_BASE, path.node, (t: Token) => { + for (const imp of path.node.specifiers) + if (isImportSpecifier(imp) || isImportDefaultSpecifier(imp)) { + const prop = getImportName(imp); + if (t instanceof AllocationSiteToken || t instanceof FunctionToken || t instanceof NativeObjectToken || t instanceof PackageObjectToken) + solver.addSubsetConstraint(a.varProducer.objPropVar(t, prop), a.varProducer.nodeVar(imp.local)); + else if (t instanceof AccessPathToken) // TODO: treat as object along with other tokens above? + solver.addAccessPath(a.canonicalizeAccessPath(new PropertyAccessPath(a.varProducer.nodeVar(path.node), prop)), a.varProducer.nodeVar(imp.local), t.ap); // TODO: describe this constraint... + } + }); + } + }, + + ExportDeclaration(path: NodePath) { + switch (path.node.type) { + case "ExportNamedDeclaration": // examples: export const { prop: name } = { prop: ... }, export { x as y } + case "ExportDefaultDeclaration": // example: export default E; + if (path.node.declaration) { + assert(!isExportNamedDeclaration(path.node) || path.node.specifiers.length === 0, "Unexpected specifiers at ExportNamedDeclaration with declaration"); + assert(!isExportNamedDeclaration(path.node) || !path.node.source, "Unexpected source at ExportNamedDeclaration with declaration"); + const decl = path.node.declaration; + switch (decl.type) { + case "FunctionDeclaration": // example: export function x() {...} + case "ClassDeclaration": { // example: export class x {...} + const from = decl.id ? decl.id : decl; // using the declaration node as constraint variable for anonymous functions and classes + assert(isExportDefaultDeclaration(path.node) || decl.id, "Unexpected missing id"); + const prop = isExportDefaultDeclaration(path.node) ? "default" : decl.id!.name; + solver.addSubsetConstraint(a.varProducer.nodeVar(from), a.varProducer.objPropVar(op.exportsObjectToken, prop)); + break; + } + case "VariableDeclaration": { // example: export var x = ... (local declaration and init value handled at rule VariableDeclarator) + function exportDeclared(lval: LVal) { + if (isIdentifier(lval)) + solver.addSubsetConstraint(a.varProducer.nodeVar(lval), a.varProducer.objPropVar(op.exportsObjectToken, lval.name)); + else if (isAssignmentPattern(lval)) + exportDeclared(lval.left); + else if (isObjectPattern(lval)) { + for (const p of lval.properties) + if (isRestElement(p)) + exportDeclared(p.argument); + else { + if (!isLVal(p.value)) + assert.fail(`Unexpected expression ${p.value.type}, expected LVal`); + exportDeclared(p.value); + } + } else if (isArrayPattern(lval)) { + for (const p of lval.elements) + if (p) + if (isRestElement(p)) + exportDeclared(p.argument); + else + exportDeclared(p); + } else + assert.fail(`Unexpected LVal type ${lval.type}`); + } + for (const decl2 of decl.declarations) + exportDeclared(decl2.id); + break; + } + default: { + if (isDeclaration(decl)) + assert.fail(`Unexpected declaration type ${decl.type} in ExportDeclaration`); + if (isExpression(decl)) + solver.addSubsetConstraint(op.expVar(decl, path), a.varProducer.objPropVar(op.exportsObjectToken, "default")); + break; + } + } + } else { + if (!isExportNamedDeclaration(path.node)) + assert.fail(`Unexpected node type ${path.node.type}`); + const node = path.node; + function getExportVar(name: string): ConstraintVar | undefined { + const m = node.source ? op.requireModule(node.source.value, a.varProducer.nodeVar(node), path) : undefined; + return m instanceof ModuleInfo ? a.varProducer.objPropVar(a.canonicalizeToken(new NativeObjectToken("exports", m)), name) : undefined; + } + for (const spec of path.node.specifiers) + switch (spec.type) { + case "ExportSpecifier": // example: export {x as y} ... + case "ExportDefaultSpecifier": // example: export x from "m" + const from = isExportDefaultSpecifier(spec) ? getExportVar("default") : node.source ? getExportVar(spec.local.name) : a.varProducer.identVar(spec.local, path); + solver.addSubsetConstraint(from, a.varProducer.objPropVar(op.exportsObjectToken, getExportName(spec.exported))); + break; + case "ExportNamespaceSpecifier": // example: export * as x from "m" + a.warnUnsupported(spec); // TODO: ExportNamespaceSpecifier, see https://babeljs.io/docs/en/babel-plugin-proposal-export-namespace-from + break; + } + + } + break; + case "ExportAllDeclaration": // example: export * from "m" + const m = op.requireModule(path.node.source.value, a.varProducer.nodeVar(path.node), path); + if (m instanceof ModuleInfo) { + const t = a.canonicalizeToken(new NativeObjectToken("exports", m)); + solver.addForAllObjectPropertiesConstraint(t, TokenListener.EXPORT_BASE, path.node, (prop: string) => { // TODO: only exporting explicitly defined properties, not unknown computed + solver.addSubsetConstraint(a.varProducer.objPropVar(t, prop), a.varProducer.objPropVar(op.exportsObjectToken, prop)); + }); + } + break; + } + }, + + ForOfStatement(path: NodePath) { + // read iterator using path.node for the temporary result + op.readIteratorValue(op.expVar(path.node.right, path), a.varProducer.nodeVar(path.node), path.node); + // assign the temporary result to the l-value + const lval = isLVal(path.node.left) ? path.node.left : path.node.left.declarations.length === 1 ? path.node.left.declarations[0]?.id : undefined; + assert(lval, "Unexpected number of declarations at for-of"); + op.assign(a.varProducer.nodeVar(path.node), lval, path.node, a.getEnclosingFunctionOrModule(path, op.moduleInfo), path, false); + // note: 'for await' is handled trivially because the same abstract object is used for the AsyncGenerator and the iterator objects + }, + + YieldExpression(path: NodePath) { + const fun = path.getFunctionParent()?.node; + assert(fun, "yield not in function?!"); + const iter = a.canonicalizeToken(new AllocationSiteToken("Iterator", fun.body, op.packageInfo)); + const iterValue = a.varProducer.objPropVar(iter, "value"); + if (path.node.argument) { + if (path.node.delegate) { + // yield* E + // constraint: ∀ i2 ∈ ⟦iterators(E)⟧: ⟦i2.value⟧ ⊆ ⟦i.value⟧ where i is the iterator object for the function + op.readIteratorValue(op.expVar(path.node.argument, path), iterValue, fun.body); + } else { + // yield E + // constraint: ⟦E⟧ ⊆ ⟦i.value⟧ where i is the iterator object for the function + solver.addSubsetConstraint(op.expVar(path.node.argument, path), iterValue); + } + } + // constraint: ⟦i.value⟧ ⊆ ⟦yield(*) E⟧ where i is the iterator object for the function + if (!isParentExpressionStatement(path)) + solver.addSubsetConstraint(iterValue, a.varProducer.nodeVar(path.node)); + }, + + AwaitExpression(path: NodePath) { + op.awaitPromise(op.expVar(path.node.argument, path), op.expVar(path.node, path), path.node); + }, + + TaggedTemplateExpression(path: NodePath) { + assert.fail("TaggedTemplateExpression should be handled by @babel/plugin-transform-template-literals"); + }, + + RegExpLiteral(path: NodePath) { + solver.addTokenConstraint(op.newRegExpToken(), a.varProducer.nodeVar(path.node)); + }, + + WithStatement(path: NodePath) { + a.warnUnsupported(path.node); + }, + + JSXElement(path: NodePath) { + const componentVar = op.expVar(path.node.openingElement.name, path); + if (componentVar) + solver.addForAllConstraint(componentVar, TokenListener.JSX_ELEMENT, path.node, (t: Token) => { + if (t instanceof AccessPathToken) + solver.addAccessPath(a.canonicalizeAccessPath(new ComponentAccessPath(componentVar)), a.varProducer.nodeVar(path.node), t.ap); + }); + } + }); + + /** + * Visits a CallExpression, OptionalCallExpression, or NewExpression. + */ + function visitCallOrNew(isNew: boolean, path: NodePath) { + const calleeVar = isExpression(path.node.callee) ? op.expVar(path.node.callee, path) : undefined; + const bp = getBaseAndProperty(path); + const baseVar = bp ? op.expVar(bp.base, path) : undefined; + const resultVar = op.expVar(path.node, path); + op.callFunction(calleeVar, baseVar, path.node.arguments, resultVar, isNew, path); + } + + /** + * Visits a MemberExpression or OptionalMemberExpression. + */ + function visitMemberExpression(path: NodePath) { + if (isAssignmentExpression(path.parent) && path.parent.left === path.node) + return; // don't treat left-hand-sides of assignments as expressions + + op.readProperty(op.expVar(path.node.object, path), getProperty(path.node), isParentExpressionStatement(path) ? undefined : a.varProducer.nodeVar(path.node), path.node, a.getEnclosingFunctionOrModule(path, op.moduleInfo)); + } +} \ No newline at end of file diff --git a/src/analysis/constraintvarproducer.ts b/src/analysis/constraintvarproducer.ts new file mode 100644 index 0000000..a60bf54 --- /dev/null +++ b/src/analysis/constraintvarproducer.ts @@ -0,0 +1,172 @@ +import { + Class, + Expression, + Function, + identifier, + Identifier, + isBigIntLiteral, + isBinaryExpression, + isBooleanLiteral, + isIdentifier, + isJSXIdentifier, + isNullLiteral, + isNumericLiteral, + isParenthesizedExpression, + isStringLiteral, + isSuper, + isUnaryExpression, + isUpdateExpression, + JSXIdentifier, + JSXMemberExpression, + JSXNamespacedName, + Node +} from "@babel/types"; +import {NodePath} from "@babel/traverse"; +import { + AccessorType, + ArgumentsVar, + ArrayValueVar, + ClassExtendsVar, + ConstraintVar, + FunctionReturnVar, + IntermediateVar, + NodeVar, + ObjectPropertyVar, + ObjectPropertyVarObj, + ThisVar +} from "./constraintvars"; +import logger from "../misc/logger"; +import {ArrayToken, ObjectToken, PackageObjectToken} from "./tokens"; +import {FilePath, sourceLocationToStringWithFile} from "../misc/util"; +import {PackageInfo} from "./infos"; +import {AnalysisState, globalLoc, undefinedIdentifier} from "./analysisstate"; +import {getClass} from "../misc/asthelpers"; + +export class ConstraintVarProducer { + + private readonly a: AnalysisState + + constructor(a: AnalysisState) { + this.a = a; + } + + /** + * Finds the constraint variable for the given expression in the current module. + * For parenthesized expressions, the inner expression is used. + * If the expression definitely cannot evaluate to a function value, undefined is returned. + * For Identifier expressions, the declaration node is used as constraint variable; + * For Super expressions, a ClassExtendsVar is used. + * For other expressions, the expression itself is used. + */ + expVar(exp: Expression | JSXIdentifier | JSXMemberExpression | JSXNamespacedName, path: NodePath): ConstraintVar | undefined { + while (isParenthesizedExpression(exp)) + exp = exp.expression; // for parenthesized expressions, use the inner expression + if (isIdentifier(exp) || isJSXIdentifier(exp)) { + const id = this.identVar(exp, path); + if (id instanceof NodeVar && id.node === undefinedIdentifier) + return undefined; + return id; + } else if (isNumericLiteral(exp) || isBigIntLiteral(exp) || isNullLiteral(exp) || isBooleanLiteral(exp) || + isStringLiteral(exp) || // note: currently skipping string literals + isUnaryExpression(exp) || isBinaryExpression(exp) || isUpdateExpression(exp)) + return undefined; // those expressions never evaluate to functions or objects and can safely be skipped + else if (isSuper(exp)) { + const cl = getClass(path); + if (!cl) { + this.a.warnUnsupported(exp, `Ignoring super in object expression at ${sourceLocationToStringWithFile(exp.loc)}`, true); // TODO: object expressions may have prototypes, e.g. __proto__ + return undefined; + } + return this.extendsVar(cl); + } + return this.a.varProducer.nodeVar(exp); // other expressions are already canonical + } + + /** + * Finds the constraint variable for the given identifier in the current module. + * If not found, it is added to the program scope (except for 'arguments'). + */ + identVar(id: Identifier | JSXIdentifier, path: NodePath): ConstraintVar { + const binding = path.scope.getBinding(id.name); + let d; + if (binding) { + d = binding.identifier; + } else { + if (id.name === "arguments") { + const fun = this.a.registerArguments(path); + return fun ? this.a.canonicalizeVar(new ArgumentsVar(fun)) : this.a.varProducer.nodeVar(id); // using the identifier itself as fallback if no enclosing function + } else { + const ps = path.scope.getProgramParent(); + d = ps.getBinding(id.name)?.identifier; + if (!d) { + d = identifier(id.name); + d.loc = globalLoc; + ps.push({id: d}); + if (logger.isDebugEnabled()) + logger.debug(`No binding for identifier ${id.name}, creating one in program scope`); + } else if (logger.isDebugEnabled()) + logger.debug(`No binding for identifier ${id.name}, using the one in program scope`); + } + } + return this.a.varProducer.nodeVar(d); // Identifiers are already canonical + } + + /** + * Finds the constraint variable for a named object property. + */ + objPropVar(obj: ObjectPropertyVarObj, prop: string, accessor: AccessorType = "normal"): ObjectPropertyVar { + if (obj instanceof ObjectToken && this.a.widened.has(obj)) + return this.packagePropVar(obj.packageInfo, prop, accessor); + return this.a.canonicalizeVar(new ObjectPropertyVar(obj, prop, accessor)); + } + + /** + * Finds the constraint variable for an array value. + */ + arrayValueVar(arr: ArrayToken): ArrayValueVar { + return this.a.canonicalizeVar(new ArrayValueVar(arr)); + } + + /** + * Finds the constraint variable for an object property for a package. + */ + packagePropVar(pck: FilePath | PackageInfo, prop: string, accessor: AccessorType = "normal"): ObjectPropertyVar { + return this.objPropVar(this.a.canonicalizeToken(new PackageObjectToken(pck instanceof PackageInfo ? pck : this.a.getModuleInfo(pck).packageInfo)), prop, accessor); + } + + /** + * Finds the constraint variable representing the return values of the given function. + */ + returnVar(fun: Function): FunctionReturnVar { + return this.a.canonicalizeVar(new FunctionReturnVar(fun)); + } + + /** + * Finds the constraint variable representing the super-class of the given class. + */ + extendsVar(cl: Class): ClassExtendsVar { + return this.a.canonicalizeVar(new ClassExtendsVar(cl)); + } + + /** + * Finds the constraint variable representing 'this' for the given function. + */ + thisVar(fun: Function): ThisVar { + return this.a.canonicalizeVar(new ThisVar(fun)); + } + + /** + * Finds the constraint variable representing the given intermediate result. + */ + intermediateVar(n: Node, label: string): IntermediateVar { + return this.a.canonicalizeVar(new IntermediateVar(n, label)); + } + + /** + * Finds the constraint variable representing the given AST node (or undefined). + */ + nodeVar(n: Node): NodeVar + nodeVar(n: Node | undefined): NodeVar | undefined + nodeVar(n: Node | undefined): NodeVar | undefined { + return n !== undefined ? this.a.canonicalizeVar(new NodeVar(n)) : undefined; + } +} \ No newline at end of file diff --git a/src/analysis/constraintvars.ts b/src/analysis/constraintvars.ts new file mode 100644 index 0000000..e94d6a0 --- /dev/null +++ b/src/analysis/constraintvars.ts @@ -0,0 +1,223 @@ +import {Class, Function, isIdentifier, Node} from "@babel/types"; +import {nodeToString, sourceLocationToStringWithFileAndEnd} from "../misc/util"; +import { + AllocationSiteToken, + ArrayToken, + FunctionToken, + NativeObjectToken, + PackageObjectToken +} from "./tokens"; +import {ModuleInfo, PackageInfo} from "./infos"; +import {IDENTIFIER_KIND} from "./astvisitor"; + +/** + * A constraint variable. + */ +export abstract class ConstraintVar { + + abstract toString(): string; + + /** + * Finds the AST node, function, module or package this constraint variable belongs to. + */ + abstract getParent(): Node | PackageInfo | ModuleInfo | undefined; + + /** + * Returns the kind of the constraint variable. + * Assumes options.variableKinds is set. + */ + getKind(): string { + return this.constructor.name; + } +} + +/** + * A constraint variable for an AST node. + */ +export class NodeVar extends ConstraintVar { + + node: Node; + + constructor(node: Node) { + super(); + this.node = node; + } + + toString(): string { + return nodeToString(this.node); + } + + getParent(): Node { + return this.node; + } + + getKind(): string { + return isIdentifier(this.node) ? `Identifier[${(this.node as any)[IDENTIFIER_KIND]}]` : this.node.type; + } +} + +/** + * Kind of ObjectPropertyVar. + */ +export type AccessorType = "get" | "set" | "normal"; + +export type ObjectPropertyVarObj = AllocationSiteToken | FunctionToken | NativeObjectToken | PackageObjectToken; + +/** + * A constraint variable for an object property. + */ +export class ObjectPropertyVar extends ConstraintVar { + + readonly obj: ObjectPropertyVarObj; + + readonly prop: string + + readonly accessor: AccessorType; + + constructor(obj: ObjectPropertyVarObj, prop: string, accessor: AccessorType = "normal") { + super(); + this.prop = prop; + this.obj = obj; + this.accessor = accessor; + } + + toString(): string { + return `${this.accessor === "get" ? "(get)" : this.accessor === "set" ? "(set)" : ""}${this.obj}.${this.prop}`; + } + + getParent() { + return this.obj instanceof AllocationSiteToken ? this.obj.allocSite : + this.obj instanceof FunctionToken ? this.obj.fun : + this.obj instanceof NativeObjectToken ? this.obj.moduleInfo : + this.obj.packageInfo; + } +} + +/** + * A constraint variable for an unknown array entry. + */ +export class ArrayValueVar extends ConstraintVar { + + readonly array: ArrayToken; + + constructor(array: ArrayToken) { + super(); + this.array = array; + } + + toString(): string { + return `${this.array}.*`; + } + + getParent(): Node { + return this.array.allocSite; + } +} + +/** + * A constraint variable for a function return. + */ +export class FunctionReturnVar extends ConstraintVar { + + readonly fun: Function; + + constructor(fun: Function) { + super(); + this.fun = fun; + } + + toString() { + return `Return[${sourceLocationToStringWithFileAndEnd(this.fun.loc)}]` + } + + getParent(): Node { + return this.fun; + } +} + +/** + * A constraint variable for 'this'. + */ +export class ThisVar extends ConstraintVar { + + readonly fun: Function; + + constructor(fun: Function) { + super(); + this.fun = fun; + } + + toString() { + return `This[${sourceLocationToStringWithFileAndEnd(this.fun.loc)}]`; + } + + getParent(): Node { + return this.fun; + } +} + +/** + * A constraint variable for 'arguments'. + */ +export class ArgumentsVar extends ConstraintVar { + + readonly fun: Function; + + constructor(fun: Function) { + super(); + this.fun = fun; + } + + toString() { + return `Arguments[${sourceLocationToStringWithFileAndEnd(this.fun.loc)}]`; + } + + getParent(): Node { + return this.fun; + } +} + +/** + * A constraint variable for the super-class of a class. + */ +export class ClassExtendsVar extends ConstraintVar { + + readonly cl: Class; + + constructor(cl: Class) { + super(); + this.cl = cl; + } + + toString() { + return `Extends[${sourceLocationToStringWithFileAndEnd(this.cl.loc)}]` + } + + getParent(): Node { + return this.cl; + } +} + +/** + * A constraint variable for an intermediate result. + */ +export class IntermediateVar extends ConstraintVar { + + readonly node: Node; + + readonly label: string; + + constructor(node: Node, label: string) { + super(); + this.node = node; + this.label = label; + } + + toString() { + return `#${this.label}[${sourceLocationToStringWithFileAndEnd(this.node.loc)}]` + } + + getParent(): Node { + return this.node; + } +} \ No newline at end of file diff --git a/src/analysis/escaping.ts b/src/analysis/escaping.ts new file mode 100644 index 0000000..d0c3d27 --- /dev/null +++ b/src/analysis/escaping.ts @@ -0,0 +1,98 @@ +import {ModuleInfo} from "./infos"; +import {AccessPathToken, AllocationSiteToken, FunctionToken, NativeObjectToken, ObjectToken, Token} from "./tokens"; +import {ConstraintVar, FunctionReturnVar, ObjectPropertyVar} from "./constraintvars"; +import {mapGetArray} from "../misc/util"; +import logger from "../misc/logger"; +import {isIdentifier} from "@babel/types"; +import Solver from "./solver"; +import {UnknownAccessPath} from "./accesspaths"; + +/** + * Finds the ObjectTokens that may be accessed from outside the module via exporting to or importing from other modules. + * Also adds UnknownAccessPath at parameters of escaping functions. + * Note: objects that are assigned to 'exports' (or to properties of such objects) are not considered escaping + * (unless also returned by an escaping function or passed as argument to an external function). + */ +export function findEscapingObjects(m: ModuleInfo, solver: Solver): Set { + const a = solver.analysisState; + const f = solver.fragmentState; + const worklist: Array = []; + const visited = new Set(); + const escaping = new Set(); + const theUnknownAccessPathToken = a.canonicalizeToken(new AccessPathToken(a.canonicalizeAccessPath(new UnknownAccessPath()))); + + /** + * Adds the tokens of the given constraint variable to the worklist if not already visited. + * Note: PackageObjectTokens and AccessPathTokens are ignored. + */ + function addToWorklist(v: ConstraintVar) { + for (const t of f.getTokens(v)) + if ((t instanceof AllocationSiteToken || t instanceof FunctionToken || t instanceof NativeObjectToken) && !visited.has(t)) { + worklist.push(t); + visited.add(t); + } + } + + // find object properties + const objprops = new Map>(); + for (const v of f.vars) + if (v instanceof ObjectPropertyVar) + mapGetArray(objprops, v.obj).push(v); + + // first round, seed worklist with module.exports, find functions accessible via property reads + addToWorklist(a.varProducer.objPropVar(a.canonicalizeToken(new NativeObjectToken("module", m)), "exports")); + const w2: Array = []; + while (worklist.length !== 0) { + const t = worklist.shift()!; // breadth-first + if (t instanceof FunctionToken) + w2.push(t); + else if (t instanceof ObjectToken || (t instanceof NativeObjectToken && t.name === "exports")) + for (const w of mapGetArray(objprops, t)) + addToWorklist(w); + } + worklist.push(...w2); + // add expressions collected during AST traversal + for (const v of solver.analysisState.maybeEscaping) + addToWorklist(v); + + // FIXME: arguments to (non-modeled) native functions should also be considered escaped? + + // second round, find objects that are accessible externally via functions and expressions found in first round + while (worklist.length !== 0) { + const t = worklist.shift()!; // breadth-first + if (t instanceof ObjectToken) { + if (logger.isDebugEnabled()) + logger.debug(`Escaping object: ${t}`); + escaping.add(t); + } + if (t instanceof FunctionToken) { + + // values returned from escaping functions are escaping + addToWorklist(a.canonicalizeVar(new FunctionReturnVar(t.fun))); + + // add UnknownAccessPath at parameters + for (const param of t.fun.params) + if (isIdentifier(param)) // TODO: Pattern|RestElement? + solver.addToken(theUnknownAccessPathToken, f.getRepresentative(a.varProducer.nodeVar(param))); + + // TODO: also consider inheritance, ClassExtendsVar? + } + + // properties of escaping objects are escaping + for (const w of mapGetArray(objprops, t)) { + addToWorklist(w); + solver.addToken(theUnknownAccessPathToken, w); + } + } + + if (logger.isVerboseEnabled()) { + const objecttokens = new Set(); + for (const [, ts] of f.getAllVarsAndTokens()) + for (const t of ts) + if (t instanceof ObjectToken) + objecttokens.add(t); + logger.verbose(`Escaping objects: ${escaping.size}/${objecttokens.size}`); + } + + return escaping; +} diff --git a/src/analysis/fragmentstate.ts b/src/analysis/fragmentstate.ts new file mode 100644 index 0000000..5a1e5d6 --- /dev/null +++ b/src/analysis/fragmentstate.ts @@ -0,0 +1,274 @@ +import {ConstraintVar, ObjectPropertyVarObj} from "./constraintvars"; +import {AllocationSiteToken, ArrayToken, FunctionToken, Token} from "./tokens"; +import {PackageInfo} from "./infos"; +import {Node} from "@babel/types"; +import assert from "assert"; + +export type ListenerID = number; + +/** + * Analysis state for a fragment (a module or a package with dependencies, depending on the analysis phase). + */ +export class FragmentState { + + /** + * The current analysis solution. + * Singleton sets are represented as plain references, larger sets are represented as ES2015 sets. + */ + private readonly tokens: Map> = new Map; + + /** + * The set of constraint variables (including those with no tokens or no subset edges, but excluding those that are redirected). + */ + readonly vars: Set = new Set; + + /** + * Indirection introduced by cycle elimination. + */ + readonly redirections: Map = new Map; + + /** + * Number of tokens for the currently analyzed fragment. (For statistics only.) + */ + numberOfTokens: number = 0; + + numberOfSubsetEdges: number = 0; + + readonly subsetEdges: Map> = new Map; + + readonly reverseSubsetEdges: Map> = new Map; // (used by solver.redirect) + + /** + * Inheritance relation. For each token, the map provides the tokens it may inherit from directly. + */ + inherits: Map> = new Map; + + reverseInherits: Map> = new Map; + + readonly arrayEntries: Map> = new Map; + + objectProperties: Map> = new Map; + + readonly tokenListeners: Map void>> = new Map; + + readonly pairListeners1: Map void]>> = new Map; + + readonly pairListeners2: Map void]>> = new Map; + + readonly pairListenersProcessed: Map>> = new Map; + + readonly packageNeighborListeners: Map void>> = new Map; + + ancestorListeners: Map void>> = new Map; + + readonly ancestorListenersProcessed: Map> = new Map; // TODO: make similar map/set for other kinds of listeners to avoid redundant listener calls? + + readonly arrayEntriesListeners: Map void>> = new Map; + + objectPropertiesListeners: Map void>> = new Map; + + readonly packageNeighbors: Map> = new Map; + + readonly postponedListenerCalls: Array<[(t: Token) => void, Token] | [(t1: AllocationSiteToken, t2: FunctionToken) => void, [AllocationSiteToken, FunctionToken]] | [(neighbor: PackageInfo) => void, PackageInfo] | [(prop: string) => void, string]> = []; + + /** + * Returns the representative of the given constraint variable. + * Also shortcuts redirections that involve multiple steps. + */ + getRepresentative(v: ConstraintVar): ConstraintVar { + let w = v; + const ws = []; + while (true) { + const w2 = this.redirections.get(w); + if (!w2) + break; + assert(ws.length < 100); + ws.push(w); + w = w2; + } + for (let i = 0; i + 1 < ws.length; i++) { + assert(ws[i] !== w); + this.redirections.set(ws[i], w); + } + return w; + } + + /** + * Returns the tokens in the solution for the given constraint variable + * (or empty if v is undefined). + */ + getTokens(v: ConstraintVar | undefined): Iterable { + if (v) { + const ts = this.tokens.get(v); + if (ts) { + if (ts instanceof Token) + return [ts]; + return ts; + } + } + return []; + } + + /** + * Returns the number of tokens in the solution for the given constraint variable, and the tokens. + */ + getTokensSize(v: ConstraintVar | undefined): [number, Iterable] { + if (v) { + const ts = this.tokens.get(v); + if (ts) { + if (ts instanceof Token) + return [1, [ts]]; + return [ts.size, ts]; + } + } + return [0, []]; + } + + /** + * Returns all constraint variables with their tokens and number of tokens. + */ + *getAllVarsAndTokens(): Iterable<[ConstraintVar, Iterable, number]> { + for (const [v, ts] of this.tokens) + if (ts instanceof Token) + yield [v, [ts], 1]; + else + yield [v, ts, ts.size]; + } + + /** + * Returns the number of tokens and a 'has' function for the given constraint variable. + */ + getSizeAndHas(v: ConstraintVar | undefined): [number, (t: Token) => boolean] { + if (v) { + const ts = this.tokens.get(v); + if (ts) { + if (ts instanceof Token) + return [1, (t: Token) => ts === t]; + return [ts.size, (t: Token) => ts.has(t)]; + } + } + return [0, (_t: Token) => false]; + } + + /** + * Returns the number of constraint variables with tokens. + */ + getNumberOfVarsWithTokens() { + return this.tokens.size; + } + + /** + * Checks whether the given variable has tokens. + */ + hasVar(v: ConstraintVar) { + return this.tokens.has(v); + } + + /** + * Removes all tokens from the given variable. + */ + deleteVar(v: ConstraintVar) { + this.tokens.delete(v); + } + + /** + * Replaces all tokens according to the given function. + */ + replaceTokens(f: (ts: Iterable) => Set) { + for (const [v, ts] of this.tokens) { + const r = f(ts instanceof Token ? [ts] : ts); + this.tokens.set(v, r.size === 1 ? r.values().next().value : r); + this.numberOfTokens += r.size - (ts instanceof Token ? 1 : ts.size); + } + } + + /** + * Adds the given token to the solution for the given constraint variable. + * @return true if not already there, false if already there + */ + addToken(t: Token, v: ConstraintVar): boolean { + const ts = this.tokens.get(v); + if (!ts) + this.tokens.set(v, t); + else if (ts instanceof Token) { + if (ts === t) + return false; + this.tokens.set(v, new Set([ts, t])); + } else { + if (ts.has(t)) + return false; + ts.add(t); + } + this.numberOfTokens++; + return true; + } + + /** + * Adds the given tokens to the solution for the given constraint variable. + * It is assumed that the given set does not contain any duplicates. + * @return the tokens that have been added, excluding those already there + */ + addTokens(ts: Iterable, v: ConstraintVar): Array { + const added: Array = []; + let vs = this.tokens.get(v); + for (const t of ts) { + let add = false; + if (!vs) { + vs = t; + this.tokens.set(v, vs); + add = true; + } else if (vs instanceof Token) { + if (vs !== t) { + vs = new Set([vs, t]); + this.tokens.set(v, vs); + add = true; + } + } else if (!vs.has(t)) { + vs.add(t); + add = true; + } + if (add) + added.push(t); + } + this.numberOfTokens += added.length; + return added; + } + + /** + * Returns the tokens the given token inherits from (reflexively and transitively). + */ + getAncestors(t: Token): Set { + const res = new Set(); + res.add(t); + const w = [t]; + while (w.length !== 0) { + const s = this.inherits.get(w.shift()!); + if (s) + for (const p of s) + if (!res.has(p)) { + res.add(p); + w.push(p); + } + } + return res; + } + + /** + * Returns the tokens that inherit from the given token (reflexively and transitively). + */ + getDescendants(t: Token): Set { + const res = new Set(); + res.add(t); + const w = [t]; + while (w.length !== 0) { + const s = this.reverseInherits.get(w.shift()!); + if (s) + for (const p of s) + if (!res.has(p)) { + res.add(p); + w.push(p); + } + } + return res; + } +} diff --git a/src/analysis/infos.ts b/src/analysis/infos.ts new file mode 100644 index 0000000..08c6e53 --- /dev/null +++ b/src/analysis/infos.ts @@ -0,0 +1,132 @@ +import {FilePath, sourceLocationToString} from "../misc/util"; +import {Function, SourceLocation} from "@babel/types"; +import {FragmentState} from "./fragmentstate"; + +/** + * Information about a package. + */ +export class PackageInfo { + + readonly name: string; // package name, "" is used for entry files if no package.json is found + + readonly version: string | undefined; // package version, undefined if not available + + readonly main: string | undefined; // package main file, undefined if not available + + readonly dir: FilePath; // absolute path to package root directory, or "." for the entry files if no package.json is found + + readonly modules: Map = new Map; // map from path relative to the package root to module info + + readonly directDependencies: Set = new Set; // the direct dependencies of this package + + readonly isEntry: boolean; // true for entry packages + + fragmentState: FragmentState | undefined = undefined; // analysis solutions after analysis of this package and its dependencies + + constructor(name: string, version: string | undefined, main: string | undefined, dir: FilePath, isEntry: boolean) { + this.name = name; + this.version = version; + this.main = main; + this.dir = dir; + this.isEntry = isEntry; + } + + toString(): string { + return `${this.name}${this.version ? `@${this.version}` : ""}`; + } +} + +export function normalizeModuleName(s: string): string { + return s.endsWith("/index.js") ? s.substring(0, s.length - 9) : // (ignoring index.json and index.node) + s.endsWith(".js") ? s.substring(0, s.length - 3) : + s.endsWith(".mjs") ? s.substring(0, s.length - 4) : s; +} + +/** + * Information about a module/file. + */ +export class ModuleInfo { + + readonly relativePath: string; // path relative to the package root + + readonly packageInfo: PackageInfo; // package containing this module + + readonly path: FilePath; // normalized file path of the representative file (in analysisstate, different paths in moduleInfos may refer to the same ModuleInfo) + + readonly functions: Map = new Map; // functions directly inside this module + + readonly isEntry: boolean; // true for entry modules + + loc: SourceLocation | null | undefined = null; // top-level source location (set by astvisitor) + + fragmentState: FragmentState | undefined = undefined; // analysis solution after local analysis of this module + + constructor(relativePath: string, packageInfo: PackageInfo, path: FilePath, isEntry: boolean) { + this.relativePath = relativePath; + this.packageInfo = packageInfo; + this.path = path; + this.isEntry = isEntry; + } + + toString(): string { + return `${this.packageInfo}:${this.relativePath}`; + } + + /** + * Returns the official name of this module, using the package name if the module is the main module, + * and otherwise stripping /index.js, .js and .mjs. + */ + getOfficialName(): string { + if (this.relativePath === this.packageInfo.main) + return this.packageInfo.name; + return normalizeModuleName(`${this.packageInfo.name}/${this.relativePath}`); + } +} + +/** + * Information about a module that is not being analyzed. + */ +export class DummyModuleInfo { // used for module files that can't be found (typically because they haven't been installed) + + readonly requireName: string; // require string (normalized but not resolved to a file) + + constructor(requireName: string) { + this.requireName = normalizeModuleName(requireName); + } + + toString(): string { + return `${this.requireName}[unresolved]`; + } + + getOfficialName(): string { + return this.requireName; + } +} + +/** + * Information about a function. + */ +export class FunctionInfo { + + readonly name: string | undefined; // function name + + readonly loc: SourceLocation | null | undefined; // function source location + + readonly moduleInfo: ModuleInfo; // module containing this function + + readonly functions: Map = new Map; // functions directly inside this function + + get packageInfo(): PackageInfo { + return this.moduleInfo.packageInfo; + } + + constructor(name: string | undefined, loc: SourceLocation | null | undefined, moduleInfo: ModuleInfo) { + this.name = name; + this.loc = loc; + this.moduleInfo = moduleInfo; + } + + toString() { + return `${this.moduleInfo}:${sourceLocationToString(this.loc)}:${this.name ?? ""}`; + } +} diff --git a/src/analysis/listeners.ts b/src/analysis/listeners.ts new file mode 100644 index 0000000..cf020cf --- /dev/null +++ b/src/analysis/listeners.ts @@ -0,0 +1,64 @@ +/** + * IDs for token listeners. + */ +export enum TokenListener { + CALL_FUNCTION_CALLEE, + CALL_FUNCTION_EXTERNAL, + CALL_FUNCTION_BASE_CALLEE, + READ_PROPERTY_BASE, + READ_PROPERTY_GETTER, + READ_PROPERTY_GETTER2, + READ_PROPERTY_BASE_DYNAMIC, + READ_PROPERTY_BASE_DYNAMIC_ARRAY, + ASSIGN_MEMBER_BASE, + ASSIGN_SETTER, + ASSIGN_DYNAMIC_BASE, + ASSIGN_DYNAMIC_BASE_ARRAY, + ASSIGN_OBJECT_PATTERN_REST, + ASSIGN_OBJECT_PATTERN_REST_PROPERTIES, + ASSIGN_ARRAY_PATTERN_REST, + ASSIGN_ARRAY_PATTERN_REST_ARRAY, + READ_ITERATOR_VALUE, + READ_ITERATOR_VALUE_ARRAY, + IMPORT_BASE, + EXPORT_BASE, + NATIVE_INVOKE_CALLBACK, + NATIVE_INVOKE_CALLBACK2, + CALL_PROMISE_EXECUTOR, + CALL_PROMISE_RESOLVE, + CALL_PROMISE_ONFULFILLED, + CALL_PROMISE_ONREJECTED, + CALL_PROMISE_ONFINALLY, + MAKE_PROMISE_RESOLVE, + MAKE_PROMISE_REJECT, + MAKE_PROMISE_ALL, + MAKE_PROMISE_ALLSETTLED, + MAKE_PROMISE_ANY, + MAKE_PROMISE_RACE, + AWAIT, + JSX_ELEMENT, + NATIVE_1, // TODO: better names to these token listeners? + NATIVE_2, + NATIVE_3, + NATIVE_4, + NATIVE_5, + NATIVE_6, + NATIVE_7, + NATIVE_8, + NATIVE_9, + NATIVE_10, + NATIVE_11, + NATIVE_12, + NATIVE_13, + NATIVE_14, + NATIVE_15, + NATIVE_16, + NATIVE_17, + NATIVE_18, + NATIVE_19, + NATIVE_20, + NATIVE_21, + NATIVE_22, + NATIVE_23, + NATIVE_24, +} diff --git a/src/analysis/modulefinder.ts b/src/analysis/modulefinder.ts new file mode 100644 index 0000000..c81ddd7 --- /dev/null +++ b/src/analysis/modulefinder.ts @@ -0,0 +1,69 @@ +import { + CallExpression, + ExportAllDeclaration, + ExportNamedDeclaration, + File, + ImportDeclaration, + isIdentifier, + isImport, + isStringLiteral +} from "@babel/types"; +import {FilePath, sourceLocationToStringWithFile} from "../misc/util"; +import traverse, {NodePath} from "@babel/traverse"; +import logger from "../misc/logger"; +import Solver from "./solver"; +import {options} from "../options"; +import {builtinModules} from "../natives/nodejs"; +import {requireResolve} from "../misc/files"; + +/** + * Scans AST for 'require', 'import' and 'export' only (no proper analysis). + */ +export function findModules(ast: File, file: FilePath, solver: Solver) { + const a = solver.analysisState; + + function requireModule(str: string, path: NodePath) { // see requireModule in operations.ts + if (!(builtinModules.has(str) || (str.startsWith("node:") && builtinModules.has(str.substring(5))))) + try { + const filepath = requireResolve(str, file, path.node.loc, a); + if (filepath) + a.reachedFile(filepath, path.getFunctionParent()?.node ?? file); + } catch { + if (options.ignoreUnresolved || options.ignoreDependencies) { + if (logger.isVerboseEnabled()) + logger.verbose(`Ignoring unresolved module '${str}' at ${sourceLocationToStringWithFile(path.node.loc)}`); + } else// TODO: special warning if the require/import is placed in a try-block, an if statement, or a switch case? + a.warn(`Unable to resolve module '${str}' at ${sourceLocationToStringWithFile(path.node.loc)}`); + } + } + + traverse(ast, { + + CallExpression(path: NodePath) { + if (((isIdentifier(path.node.callee) && + path.node.callee.name === "require" && + !path.scope.getBinding(path.node.callee.name)) || + isImport(path.node.callee)) && + path.node.arguments.length >= 1) { + const arg = path.node.arguments[0]; + if (isStringLiteral(arg)) + requireModule(arg.value, path); + else + a.error(`Unhandled 'require' at ${sourceLocationToStringWithFile(path.node.loc)}`); + } + }, + + ImportDeclaration(path: NodePath) { + requireModule(path.node.source.value, path); + }, + + ExportAllDeclaration(path: NodePath) { + requireModule(path.node.source.value, path); + }, + + ExportNamedDeclaration(path: NodePath) { + if (path.node.source) + requireModule(path.node.source.value, path); + } + }); +} \ No newline at end of file diff --git a/src/analysis/operations.ts b/src/analysis/operations.ts new file mode 100644 index 0000000..dd225d8 --- /dev/null +++ b/src/analysis/operations.ts @@ -0,0 +1,700 @@ +import { + CallExpression, + Expression, + Function, + Identifier, + isArrayPattern, + isAssignmentPattern, + isExportDeclaration, + isExpression, + isIdentifier, + isImport, + isLVal, + isMemberExpression, + isObjectPattern, + isParenthesizedExpression, + isRestElement, + isStringLiteral, + JSXIdentifier, + JSXMemberExpression, + JSXNamespacedName, + LVal, + NewExpression, + Node, + OptionalCallExpression, + ParenthesizedExpression +} from "@babel/types"; +import {NodePath} from "@babel/traverse"; +import {getKey, getProperty, isMaybeUsedAsPromise, isParentExpressionStatement} from "../misc/asthelpers"; +import {AccessPathToken, AllocationSiteToken, ArrayToken, ClassToken, FunctionToken, NativeObjectToken, ObjectToken, PackageObjectToken, Token} from "./tokens"; +import {ArgumentsVar, ConstraintVar, IntermediateVar, NodeVar} from "./constraintvars"; +import {CallResultAccessPath, IgnoredAccessPath, ModuleAccessPath, PropertyAccessPath, UnknownAccessPath} from "./accesspaths"; +import Solver from "./solver"; +import {AnalysisState, globalLoc} from "./analysisstate"; +import {DummyModuleInfo, FunctionInfo, ModuleInfo, normalizeModuleName, PackageInfo} from "./infos"; +import logger from "../misc/logger"; +import {builtinModules} from "../natives/nodejs"; +import {requireResolve} from "../misc/files"; +import {options} from "../options"; +import {FilePath, getOrSet, isArrayIndex, nodeToString, sourceLocationToStringWithFile} from "../misc/util"; +import assert from "assert"; +import {ARRAY_PROTOTYPE, FUNCTION_PROTOTYPE, MAP_KEYS, MAP_VALUES, OBJECT_PROTOTYPE, PROMISE_FULFILLED_VALUES, PROMISE_PROTOTYPE, REGEXP_PROTOTYPE, SET_VALUES} from "../natives/ecmascript"; +import {SpecialNativeObjects} from "../natives/nativebuilder"; +import {ConstraintVarProducer} from "./constraintvarproducer"; +import {TokenListener} from "./listeners"; +import micromatch from "micromatch"; +import {callPromiseResolve} from "../natives/nativehelpers"; + +/** + * Models of core JavaScript operations used by astvisitor and nativehelpers. + */ +export class Operations { + + readonly file: FilePath; + + readonly solver: Solver; + + readonly globals: Array; + + readonly natives: SpecialNativeObjects + + readonly a: AnalysisState; // shortcut to this.solver.analysisState + + readonly varProducer: ConstraintVarProducer; // shortcut to this.solver.analysisState.varProducer + + readonly moduleInfo: ModuleInfo; + + readonly packageInfo: PackageInfo; + + readonly packageObjectToken: PackageObjectToken; + + readonly exportsObjectToken: NativeObjectToken; + + readonly theUnknownAccessPath: UnknownAccessPath; + + readonly theIgnoredModuleAccessPath: IgnoredAccessPath; + + constructor(file: FilePath, solver: Solver, globals: Array, natives: SpecialNativeObjects) { + this.file = file; + this.solver = solver; + this.globals = globals; + this.natives = natives; + + this.a = this.solver.analysisState; + this.varProducer = this.a.varProducer; + + this.moduleInfo = this.a.getModuleInfo(file); + this.packageInfo = this.moduleInfo.packageInfo; + this.packageObjectToken = this.a.canonicalizeToken(new PackageObjectToken(this.packageInfo)); + this.exportsObjectToken = this.a.canonicalizeToken(new NativeObjectToken("exports", this.moduleInfo)); + this.theUnknownAccessPath = this.a.canonicalizeAccessPath(new UnknownAccessPath()); + this.theIgnoredModuleAccessPath = this.a.canonicalizeAccessPath(new IgnoredAccessPath()); + } + + /** + * Finds the constraint variable for the given expression in the current module using ConstraintVarProducer.expVar. + * Also adds @Unknown and a subset constraint for globalThis.E if the given expression E is an implicitly declared global variable. + */ + expVar(exp: Expression | JSXIdentifier | JSXMemberExpression | JSXNamespacedName, path: NodePath): ConstraintVar | undefined { + const v = this.varProducer.expVar(exp, path); + + // if the expression is a variable that has not been declared normally... + if (v instanceof NodeVar && isIdentifier(v.node) && v.node.loc === globalLoc) { + + // the variable may be a property of globalThis + // constraint: globalThis.X ∈ ⟦X⟧ + this.solver.addSubsetConstraint(this.varProducer.objPropVar(this.natives.get("globalThis")!, v.node.name), v); + + // the variable may be declared explicitly by unknown code + // constraint: @Unknown ∈ ⟦X⟧ + this.solver.addAccessPath(this.theUnknownAccessPath, v); + } + return v; + } + + /** + * Models calling a function. + * @param calleeVar constraint variable describing the callee, undefined if not applicable + * @param baseVar constraint variable describing the method call base, undefined if not applicable + * @param args arguments array of arguments + * @param resultVar constraint variable describing the call result, undefined if not applicable + * @param isNew true if this is a 'new' call + * @param path path of the call expression + */ + callFunction(calleeVar: ConstraintVar | undefined, baseVar: ConstraintVar | undefined, args: CallExpression["arguments"], + resultVar: ConstraintVar | undefined, isNew: boolean, path: NodePath) { + const caller = this.a.getEnclosingFunctionOrModule(path, this.moduleInfo); + let pars: NodePath = path; // (workaround to match dyn.ts which has wrong source location for calls in parenthesized expressions) + while (isParenthesizedExpression(pars.parentPath!.node)) + pars = pars.parentPath!; + this.a.registerCall(pars.node, this.moduleInfo); + + // collect special information for pattern matcher + if (isParentExpressionStatement(pars)) + this.a.registerCallWithUnusedResult(path.node); + if (isMaybeUsedAsPromise(path)) + this.a.registerCallWithResultMaybeUsedAsPromise(path.node); + this.a.registerInvokedExpression(path.node.callee); + + const a = this.a; + function* getStrings(exp: Expression | any): Iterable { + if (isStringLiteral(exp)) + yield exp.value; + else // TODO: currently supporting only string literals at 'require' and 'import' + a.warnUnsupported(path.node, "Unhandled 'require'", true); + } + + // expression E0(E1,...,En) or new E0(E1,...,En) + // constraint: ∀ functions t ∈ ⟦E0⟧: ... + this.solver.addForAllConstraint(calleeVar, TokenListener.CALL_FUNCTION_CALLEE, path.node, (t: Token) => { + if (t instanceof FunctionToken) { + this.a.registerCallEdge(pars.node, caller, this.a.functionInfos.get(t.fun)!); + if (t.moduleInfo !== this.moduleInfo) + this.a.registerEscapingArguments(args, path); + const hasArguments = this.a.functionsWithArguments.has(t.fun); + const argumentsToken = hasArguments ? this.a.canonicalizeToken(new ArrayToken(t.fun.body, this.packageInfo)) : undefined; + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + // constraint: ...: ⟦Ei⟧ ⊆ ⟦Xi⟧ for each argument/parameter i (Xi may be a pattern) + if (isExpression(arg)) { + const argVar = this.expVar(arg, path); + if (i < t.fun.params.length) + this.assign(argVar, t.fun.params[i], pars.node, caller, path, true, isRestElement(t.fun.params[i]) ? args.slice(i) : undefined, t.fun); + // constraint ...: ⟦Ei⟧ ⊆ ⟦t_arguments[i]⟧ for each argument i if the function uses 'arguments' + if (hasArguments) + this.solver.addSubsetConstraint(argVar, this.varProducer.objPropVar(argumentsToken!, String(i))); + } else if (arg) + this.a.warnUnsupported(arg, "SpreadElement in arguments", true); // TODO: SpreadElement in arguments + } + // constraint: ...: ⟦ret_t⟧ ⊆ ⟦(new) E0(E1,...,En)⟧ + if (!isParentExpressionStatement(pars)) + this.solver.addSubsetConstraint(this.varProducer.returnVar(t.fun), resultVar); + // constraint: ...: t_arguments ∈ ⟦t_arguments⟧ if the function uses 'arguments' + if (hasArguments) { + const argumentsVar = this.a.canonicalizeVar(new ArgumentsVar(t.fun)); + this.solver.addTokenConstraint(argumentsToken!, argumentsVar); + } + + } else if (t instanceof NativeObjectToken) { + this.a.registerCall(pars.node, this.moduleInfo, {native: true}); + if (t.invoke && (!isNew || t.constr)) + t.invoke({path, solver: this.solver, op: this, moduleInfo: this.moduleInfo, natives: this.natives}); + + if (t.name === "require" && args.length >= 1) { + + // require(...) + for (const str of getStrings(args[0])) + this.requireModule(str, resultVar, path); + } + + } else if (t instanceof AllocationSiteToken && (t.kind === "PromiseResolve" || t.kind === "PromiseReject") && !isNew) { + callPromiseResolve(t, args, path, this); + + } else if (t instanceof AccessPathToken) { + assert(calleeVar); + this.a.registerCall(pars.node, this.moduleInfo, {external: true}); + this.a.registerEscapingArguments(args, path); + + // constraint: add CallResultAccessPath + this.solver.addAccessPath(this.a.canonicalizeAccessPath(new CallResultAccessPath(calleeVar)), resultVar, t.ap); + + // constraint: assign UnknownAccessPath to arguments to function arguments for external functions, also add (artificial) call edge + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + if (isExpression(arg)) + this.solver.addForAllConstraint(this.expVar(arg, path), TokenListener.CALL_FUNCTION_EXTERNAL, arg, (at: Token) => { + if (at instanceof FunctionToken) { + this.a.registerCallEdge(pars.node, caller, this.a.functionInfos.get(at.fun)!, {external: true}); + for (let j = 0; j < at.fun.params.length; j++) + if (isIdentifier(at.fun.params[j])) // TODO: non-identifier parameters? + this.solver.addAccessPath(this.theUnknownAccessPath, this.a.varProducer.nodeVar(at.fun.params[j])); + } + }); + else + this.a.warnUnsupported(arg, "SpreadElement in arguments to external function"); // TODO: SpreadElement in arguments to external function + } + // TODO: also add arguments (and everything reachable from them) to escaping? + // TODO: also add UnknownAccessPath to properties of object arguments for external functions? (see also TODO at AssignmentExpression) + + // TODO: if caller is MemberExpression with property 'apply', 'call' or 'bind', treat as call to the native function of that name (relevant for lodash/atomizer TAPIR benchmark) + } + + // if 'new' and not a native object with an invoke function and not an access path token... + if (isNew && (!(t instanceof NativeObjectToken) || !t.invoke) && !(t instanceof AccessPathToken)) { + + // constraint: t ∈ ⟦new E0(E1,...,En)⟧ where t is the current PackageObjectToken + this.solver.addTokenConstraint(this.packageObjectToken, resultVar); // TODO: use allocation-site abstraction for 'new'? + } + }); + + // constraint: if E0 is a member expression E.m: ∀ t ∈ ⟦E⟧, functions f ∈ ⟦E0⟧: if f uses 'this'... + this.solver.addForAllConstraint(calleeVar, TokenListener.CALL_FUNCTION_BASE_CALLEE, path.node, (ft: Token) => { + if (ft instanceof FunctionToken && this.a.functionsWithThis.has(ft.fun)) + + // constraint: ... ⟦E⟧ ⊆ ⟦this_f⟧ + this.solver.addSubsetConstraint(baseVar, this.varProducer.thisVar(ft.fun)); // TODO: introduce special subset edge that only propagates FunctionToken and AllocationSiteToken? + }); + + // 'import' expression + if (calleeVar instanceof NodeVar && isImport(calleeVar.node) && args.length >= 1) { + const v = this.a.canonicalizeVar(new IntermediateVar(path.node, "import")); + for (const str of getStrings(args[0])) + this.requireModule(str, v, path); + const promise = this.newPromiseToken(path.node); + this.solver.addTokenConstraint(promise, this.expVar(path.node, path)); + this.solver.addSubsetConstraint(v, this.varProducer.objPropVar(promise, PROMISE_FULFILLED_VALUES)); + } + } + + /** + * Models reading a property of an object. + * @param base constraint variable representing the base variable + * @param prop property name, undefined if unknown + * @param dst constraint variable for the result, or undefined if not applicable + * @param node AST node where the operation occurs (used for constraint keys etc.) + * @param enclosing enclosing function/module of the AST node + */ + readProperty(base: ConstraintVar | undefined, prop: string | undefined, dst: ConstraintVar | undefined, node: Node, enclosing: FunctionInfo | ModuleInfo) { + this.solver.collectPropertyRead(dst, base, this.packageObjectToken); + + // expression E.p or E["p"] or E[i] + if (prop !== undefined) { + + const readFromGetter = (t: Token) => { + if (t instanceof FunctionToken && t.fun.params.length === 0) { + if (dst) + this.solver.addSubsetConstraint(this.varProducer.returnVar(t.fun), dst); + if (base && this.a.functionsWithThis.has(t.fun)) + this.solver.addSubsetConstraint(base, this.varProducer.thisVar(t.fun)); + this.a.registerCall(node, this.moduleInfo, {accessor: true}); + this.a.registerCallEdge(node, enclosing, this.a.functionInfos.get(t.fun)!, {accessor: true}); + } + } + + // constraint: ∀ objects t ∈ ⟦E⟧: ... + this.solver.addForAllConstraint(base, TokenListener.READ_PROPERTY_BASE, node, (t: Token) => { + + // constraint: ... ∀ ancestors t2 of t: ... + this.solver.addForAllAncestorsConstraint(t, node, (t2: Token) => { + + if (t2 instanceof AllocationSiteToken || t2 instanceof FunctionToken || t2 instanceof NativeObjectToken || t2 instanceof PackageObjectToken) { + + // constraint: ... ⟦t2.p⟧ ⊆ ⟦E.p⟧ + if (dst) + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t2, prop), dst); // TODO: exclude AccessPathTokens? + + // constraint: ... ∀ functions t3 ∈ ⟦(get)t2.p⟧: ⟦ret_t3⟧ ⊆ ⟦E.p⟧ + this.solver.addForAllConstraint(this.varProducer.objPropVar(t2, prop, "get"), TokenListener.READ_PROPERTY_GETTER, node, readFromGetter); + + if (t2 instanceof PackageObjectToken) { + // TODO: also reading from neighbor packages if t2 is a PackageObjectToken... + this.solver.addForAllPackageNeighborsConstraint(t2.packageInfo, node, (neighbor: PackageInfo) => { + if (dst) + this.solver.addSubsetConstraint(this.varProducer.packagePropVar(neighbor, prop), dst); // TODO: exclude AccessPathTokens? + this.solver.addForAllConstraint(this.varProducer.packagePropVar(neighbor, prop, "get"), TokenListener.READ_PROPERTY_GETTER2, node, readFromGetter); + }); + + } else if (t2 instanceof ArrayToken) { + if (isArrayIndex(prop)) { + + // constraint: ... ⟦t2.*⟧ ⊆ ⟦E.p⟧ + this.solver.addSubsetConstraint(this.varProducer.arrayValueVar(t2), dst); + } + } + + } else if (base && t2 instanceof AccessPathToken) { + + // constraint: ... if t2 is access path, @E.p ∈ ⟦E.p⟧ + this.solver.addAccessPath(this.a.canonicalizeAccessPath(new PropertyAccessPath(base, prop)), this.a.varProducer.nodeVar(node), t2.ap); + } + }); + + if (t instanceof FunctionToken && prop === "prototype") { // FIXME: also model reads from "__proto__" + + // constraint: ... p="prototype" ∧ t is a function ⇒ k ∈ ⟦E.p⟧ where k represents the package + if (dst) + this.solver.addTokenConstraint(this.packageObjectToken, dst); // FIXME: use special prototype objects instead of PackageObjectToken! + } + }); + + } else { // TODO: handle dynamic property reads? + + this.a.registerEscaping(base); // unknown properties of the base object may escape + this.solver.addAccessPath(this.theUnknownAccessPath, dst); + + // constraint: ∀ arrays t ∈ ⟦E⟧: ... + if (dst) + this.solver.addForAllConstraint(base, TokenListener.READ_PROPERTY_BASE_DYNAMIC, node, (t: Token) => { + if (t instanceof ArrayToken) { + + // constraint: ... ⟦t.*⟧ ⊆ ⟦E[i]⟧ + this.solver.addSubsetConstraint(this.varProducer.arrayValueVar(t), dst); + + // constraint: ...: ⟦t.p⟧ ⊆ ⟦E[i]⟧ where p is a property of t + this.solver.addForAllArrayEntriesConstraint(t, TokenListener.READ_PROPERTY_BASE_DYNAMIC_ARRAY, node, (prop: string) => { + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, prop), dst); + }); + // TODO: ignoring reads from prototype chain + + } else { // TODO: assuming dynamic reads from arrays only read array indices + if (logger.isInfoEnabled()) + this.a.registerUnhandledDynamicPropertyRead(node); + } + }); + + // TODO: PropertyAccessPaths for dynamic property reads? + } + // TODO: special treatment for E.prototype? and other standard properties? + // TODO: computed property assignments (with known prefix/suffix) (also handle PrivateName properties?) + // TODO: warn at reads from ‘arguments.callee’ + } + + /** + * Models 'require' and 'import'. + * If path denotes an ExportDeclaration, no constraints are generated. + * Returns the module info object, or undefined if not available. + */ + requireModule(str: string, resultVar: ConstraintVar | undefined, path: NodePath): ModuleInfo | DummyModuleInfo | undefined { // see requireModule in modulefinder.ts + const reexport = isExportDeclaration(path.node); + let m: ModuleInfo | DummyModuleInfo | undefined; + if (builtinModules.has(str) || (str.startsWith("node:") && builtinModules.has(str.substring(5)))) { + + if (!reexport) { + // standard library module: model with UnknownAccessPath + // constraint: @Unknown ∈ ⟦require(...)⟧ + this.solver.addAccessPath(this.theUnknownAccessPath, resultVar); + // TODO: models for parts of the standard library + } else + this.a.warnUnsupported(path.node, `Ignoring re-export from built-in module '${str}'`); // TODO: re-exporting from built-in module + } else { + try { + + // try to locate the module + const filepath = requireResolve(str, this.file, path.node.loc, this.a); + if (filepath) { + + // register that the module is reached + m = this.a.reachedFile(filepath, path.getFunctionParent()?.node ?? this.file); + + if (!reexport) { + // constraint: ⟦module_m.exports⟧ ⊆ ⟦require(...)⟧ where m denotes the module being loaded + this.solver.addSubsetConstraint(this.varProducer.objPropVar(this.a.canonicalizeToken(new NativeObjectToken("module", m)), "exports"), resultVar); + } + } + } catch { + if (options.ignoreUnresolved || options.ignoreDependencies) { + if (logger.isVerboseEnabled()) + logger.verbose(`Ignoring unresolved module '${str}' at ${sourceLocationToStringWithFile(path.node.loc)}`); + } else // TODO: special warning if the require/import is placed in a try-block, an if statement, or a switch case? + this.a.warn(`Unable to resolve module '${str}' at ${sourceLocationToStringWithFile(path.node.loc)}`); // TODO: may report duplicate error messages + + // couldn't find module file (probably hasn't been installed), use a DummyModuleInfo if absolute module name + if (!"./#".includes(str[0])) + m = getOrSet(this.a.dummyModuleInfos, str, () => new DummyModuleInfo(str)); + } + + if (m) { + + // add access path token + const analyzed = m instanceof ModuleInfo && (!options.ignoreDependencies || this.a.entryFiles.has(m.path)); + if (!analyzed || options.vulnerabilities) { + const s = normalizeModuleName(str); + const tracked = options.trackedModules && options.trackedModules.find(e => + micromatch.isMatch(m!.getOfficialName(), e) || micromatch.isMatch(s, e)) + this.solver.addAccessPath(tracked ? + this.a.canonicalizeAccessPath(new ModuleAccessPath(m, s)) : + this.theIgnoredModuleAccessPath, + resultVar); + } + + this.a.registerRequireCall(path.node, this.a.getEnclosingFunctionOrModule(path, this.moduleInfo), m); + } + } + return m; + } + + /** + * Models an assignment from a constraint variable to an l-value. + * @param src source constraint variable + * @param dst destination l-value + * @param node AST node of the assignment (used for setter call edges) + * @param enclosing enclosing function/module of the source + * @param path path of operation (at calls, this is the path of the call site, not the function definition) + * @param isCall true if the assignment is for parameter passing at a function call, otherwise false + * @param rest rest arguments, undefined if not applicable + * @param fun a function if the assignment is for parameter passing at a function call, otherwise undefined + */ + assign(src: ConstraintVar | undefined, dst: LVal | ParenthesizedExpression, node: Node, enclosing: FunctionInfo | ModuleInfo, path: NodePath, isCall: boolean, rest?: CallExpression["arguments"], fun?: Function) { + while (isParenthesizedExpression(dst)) + dst = dst.expression as LVal | ParenthesizedExpression; // for parenthesized expressions, use the inner expression (the definition of LVal in @babel/types misses ParenthesizedExpression) + if (isIdentifier(dst)) { + + // X = E + // constraint: ⟦E⟧ ⊆ ⟦X⟧ + const lVar = isCall ? this.a.varProducer.nodeVar(dst) : this.varProducer.identVar(dst, path); + this.solver.addSubsetConstraint(src, lVar); + + if (fun) + this.a.registerFunctionParameter(lVar, fun); // TODO: also register for some of the cases below? + + } else if (isMemberExpression(dst)) { + const lVar = this.expVar(dst.object, path); + const prop = getProperty(dst); + if (prop !== undefined) { + + // E1.p = E2 + + const writeToSetter = (t: Token) => { + if (t instanceof FunctionToken && t.fun.params.length === 1) { + this.assign(src, t.fun.params[0], node, enclosing, path, true); // TODO: recursive call to assign, skip if already called with these arguments? + if (this.a.functionsWithThis.has(t.fun)) + this.solver.addSubsetConstraint(lVar, this.varProducer.thisVar(t.fun)); + this.a.registerCall(node, this.moduleInfo, {accessor: true}); + this.a.registerCallEdge(node, enclosing, this.a.functionInfos.get(t.fun)!, {accessor: true}); + } + } + + // constraint: ∀ objects t ∈ ⟦E1⟧: ... + this.solver.addForAllConstraint(lVar, TokenListener.ASSIGN_MEMBER_BASE, path.node, (t: Token) => { + if (t instanceof AllocationSiteToken || t instanceof FunctionToken || t instanceof NativeObjectToken || t instanceof PackageObjectToken) { + + // FIXME: special treatment of writes to "prototype" and "__proto__" + + // constraint: ...: ⟦E2⟧ ⊆ ⟦t.p⟧ + this.solver.addSubsetConstraint(src, this.varProducer.objPropVar(t, prop)); + + // constraint: ...: ∀ functions t2 ∈ ⟦(set)t.p⟧: ⟦E2⟧ ⊆ ⟦x⟧ where x is the parameter of t2 + this.solver.addForAllConstraint(this.varProducer.objPropVar(t, prop, "set"), TokenListener.ASSIGN_SETTER, path.node, writeToSetter); + + } else if (lVar && t instanceof AccessPathToken) { + + // constraint: ...: ⟦E2⟧ ⊆ ⟦k.p⟧ where k is the current PackageObjectToken + this.solver.addSubsetConstraint(src, this.varProducer.packagePropVar(this.packageInfo, prop)); + + // collect property write operation @E1.p + this.solver.addAccessPath(this.a.canonicalizeAccessPath(new PropertyAccessPath(lVar, prop)), this.a.varProducer.nodeVar(path.node), t.ap); + + // TODO: the following apparently has no effect on call graph or pattern matching... + // // constraint: assign UnknownAccessPath to arguments to function values for external functions + // this.solver.addForAllConstraint2(eVar, TokenListener.ASSIGN_..., path.node, (at: Token) => { + // if (at instanceof FunctionToken) { + // for (let j = 0; j < at.fun.params.length; j++) + // if (isIdentifier(at.fun.params[j])) // TODO: non-identifier parameters? + // this.solver.addAccessPath(theUnknownAccessPath, at.fun.params[j]); + // } + // }); + // TODO: also add the assigned value (and everything reachable from it) to escaping? + } + }); + + // TODO: special treatment for E.prototype? and other standard properties? + + } else { + + // E1[...] = E2 + this.solver.collectDynamicPropertyWrite(lVar); + this.a.registerEscaping(src); + + // constraint: ∀ arrays t ∈ ⟦E1⟧: ... + this.solver.addForAllConstraint(lVar, TokenListener.ASSIGN_DYNAMIC_BASE, path.node, (t: Token) => { + if (t instanceof ArrayToken) { + + // constraint: ...: ⟦E2⟧ ⊆ ⟦t.*⟧ + this.solver.addSubsetConstraint(src, this.varProducer.arrayValueVar(t)); + + // TODO: write to array setters also? + + } else { + if (logger.isInfoEnabled() && src) + this.a.registerUnhandledDynamicPropertyWrite(path.node, src, options.warningsUnsupported && logger.isVerboseEnabled() ? path.getSource() : undefined); + } + }); + // TODO: computed property assignments (with known prefix/suffix) + + // TODO: PropertyAccessPath for dynamic property writes? + } + // TODO: warn at writes to properties of ‘arguments’ + + } else if (isAssignmentPattern(dst)) + // delegate to dst.left (the default value dst.right is handled at AssignmentPattern) + this.assign(src, dst.left, dst, enclosing, path, isCall, undefined, fun); + else if (isObjectPattern(dst)) { + const matched = new Set(); + for (const p of dst.properties) + if (isRestElement(p)) { + // read the remaining object properties of src into a fresh object at p + const t = this.newObjectToken(p); + this.solver.addForAllConstraint(src, TokenListener.ASSIGN_OBJECT_PATTERN_REST, p, (t2: Token) => { + if (t2 instanceof AllocationSiteToken || t2 instanceof FunctionToken || t2 instanceof NativeObjectToken || t2 instanceof PackageObjectToken) { + this.solver.addForAllObjectPropertiesConstraint(t2, TokenListener.ASSIGN_OBJECT_PATTERN_REST_PROPERTIES, p, (prop: string) => { // TODO: only copying explicit properties, not unknown computed + if (!matched.has(prop)) + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t2, prop), this.varProducer.objPropVar(t, prop)); + // TODO: PropertyAccessPaths for rest elements in destructuring assignments for objects? + }); + } + }); + this.solver.addTokenConstraint(t, this.a.varProducer.nodeVar(p)); + // assign the object to the sub-l-value + this.assign(this.a.varProducer.nodeVar(p), p.argument, dst, enclosing, path, isCall, undefined, fun); + } else { + const prop = getKey(p); + if (prop) { + matched.add(prop); + // read the property using p for the temporary result + this.readProperty(src, prop, this.a.varProducer.nodeVar(p), p, enclosing); + // assign the temporary result at p to the locations represented by p.value + if (!isLVal(p.value)) + assert.fail(`Unexpected expression ${p.value.type}, expected LVal at ${sourceLocationToStringWithFile(p.value.loc)}`); + this.assign(this.a.varProducer.nodeVar(p), p.value, dst, enclosing, path, isCall, undefined, fun); + } + } + } else if (isArrayPattern(dst)) { + for (const [i, p] of dst.elements.entries()) + if (p) + if (isRestElement(p)) { + // read the remaining array elements of src into a fresh array at p + const t = this.newArrayToken(p); + this.solver.addForAllConstraint(src, TokenListener.ASSIGN_ARRAY_PATTERN_REST, p, (t2: Token) => { + if (t2 instanceof ArrayToken) { + this.solver.addForAllArrayEntriesConstraint(t2, TokenListener.ASSIGN_ARRAY_PATTERN_REST_ARRAY, p, (prop: string) => { + const newprop = parseInt(prop) - i; + if (newprop >= 0) + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t2, prop), this.varProducer.objPropVar(t, String(newprop))); + }); + this.solver.addSubsetConstraint(this.varProducer.arrayValueVar(t2), this.varProducer.arrayValueVar(t)); + } // TODO: PropertyAccessPaths for rest elements in destructuring assignments for arrays? + }); + this.solver.addTokenConstraint(t, this.a.varProducer.nodeVar(p)); + // assign the array to the sub-l-value + this.assign(this.a.varProducer.nodeVar(p), p.argument, dst, enclosing, path, isCall, undefined, fun); + } else { + // read the property using p for the temporary result + this.readProperty(src, String(i), this.a.varProducer.nodeVar(p), p, enclosing); + // assign the temporary result at p to the locations represented by p + this.assign(this.a.varProducer.nodeVar(p), p, dst, enclosing, path, isCall, undefined, fun); + } + } else { + if (!isRestElement(dst)) + assert.fail(`Unexpected LVal type ${dst.type} at ${sourceLocationToStringWithFile(dst.loc)}`); + if (!rest) { + this.a.warnUnsupported(node, `rest arguments missing ${nodeToString(dst)}`); // FIXME: may occur when called (spuriously?) from writeToSetter (try analyzing package enzyme or jsdom) + return; + } + // read the remaining arguments into a fresh array at dst + const t = this.newArrayToken(dst); + for (const [i, arg] of rest.entries()) + if (isExpression(arg)) // TODO: SpreadElement in arguments (warning emitted at visitCallOrNew) + this.solver.addSubsetConstraint(this.expVar(arg, path), this.varProducer.objPropVar(t, String(i))); + this.solver.addTokenConstraint(t, this.a.varProducer.nodeVar(dst)); + // assign the array to the sub-l-value + this.assign(this.a.varProducer.nodeVar(dst), dst.argument, dst, enclosing, path, isCall, undefined, fun); + } + } + + /** + * Models reading an iterator value. + * @param src source expression evaluating to iterable + * @param dst destination constraint variable + * @param node node used for constraint keys and array allocation site + */ + readIteratorValue(src: ConstraintVar | undefined, dst: ConstraintVar, node: Node) { + this.solver.addForAllConstraint(src, TokenListener.READ_ITERATOR_VALUE, node, (t: Token) => { + if (t instanceof AllocationSiteToken) + switch (t.kind) { + case "Array": + this.solver.addSubsetConstraint(this.varProducer.arrayValueVar(t), dst); + this.solver.addForAllArrayEntriesConstraint(t, TokenListener.READ_ITERATOR_VALUE_ARRAY, node, (prop: string) => { + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, prop), dst); + }); + break; + case "Set": + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, SET_VALUES), dst); + break; + case "Map": + const pair = this.newArrayToken(node); + this.solver.addTokenConstraint(pair, dst); + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, MAP_KEYS), this.varProducer.objPropVar(pair, "0")); + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, MAP_VALUES), this.varProducer.objPropVar(pair, "1")); + break; + case "Iterator": + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, "value"), dst); + break; + } // TODO: also handle TypedArray (see also nativebuilder.ts:returnIterator) + // TODO: also handle user-defined... + }); + } + + /** + * Creates a new ObjectToken that inherits from Object.prototype + * (or, if allocation site is disabled or the token has been widened, returns the current PackageObjectToken). + */ + newObjectToken(n: Node): ObjectToken | PackageObjectToken { + if (options.alloc) { + const t = this.a.canonicalizeToken(new ObjectToken(n, this.packageInfo)); + if (!(this.a.widened && this.a.widened.has(t))) { + this.solver.addInherits(t, this.natives.get(OBJECT_PROTOTYPE)!); + return t; + } + } + return this.packageObjectToken; + } + + /** + * Creates a new ArrayToken that inherits from Array.prototype. + */ + newArrayToken(n: Node): ArrayToken { + const t = this.a.canonicalizeToken(new ArrayToken(n, this.packageInfo)); + this.solver.addInherits(t, this.natives.get(ARRAY_PROTOTYPE)!); + return t; + } + + /** + * Creates a new ClassToken that inherits from Function.prototype. + */ + newClassToken(n: Node): ClassToken { + const t = this.a.canonicalizeToken(new ClassToken(n, this.packageInfo)); + this.solver.addInherits(t, this.natives.get(FUNCTION_PROTOTYPE)!); + return t; + } + + /** + * Creates a new FunctionToken that inherits from Function.prototype. + */ + newFunctionToken(fun: Function): FunctionToken { + const t = this.a.canonicalizeToken(new FunctionToken(fun, this.moduleInfo)); + this.solver.addInherits(t, this.natives.get(FUNCTION_PROTOTYPE)!); + return t; + } + + /** + * Creates a PackageObjectToken of kind RegExp that inherits from RegExp.prototype. + */ + newRegExpToken(): PackageObjectToken { + const t = this.a.canonicalizeToken(new PackageObjectToken(this.packageInfo, "RegExp")); + this.solver.addInherits(t, this.natives.get(REGEXP_PROTOTYPE)!); + return t; + } + + /** + * Creates a AllocationSiteToken of kind Promise that inherits from Promise.prototype. + */ + newPromiseToken(n: Node): AllocationSiteToken { + const t = this.a.canonicalizeToken(new AllocationSiteToken("Promise", n, this.packageInfo)); + this.solver.addInherits(t, this.natives.get(PROMISE_PROTOTYPE)!); + return t; + } + + /** + * Models 'await'. + */ + awaitPromise(arg: ConstraintVar | undefined, res: ConstraintVar | undefined, node: Node) { + if (!arg || !res) + return; + this.solver.addForAllConstraint(arg, TokenListener.AWAIT, node, (t: Token) => { + if (t instanceof AllocationSiteToken && t.kind === "Promise") + this.solver.addSubsetConstraint(this.varProducer.objPropVar(t, PROMISE_FULFILLED_VALUES), res); + else + this.solver.addTokenConstraint(t, res); + }); + } +} diff --git a/src/analysis/solver.ts b/src/analysis/solver.ts new file mode 100644 index 0000000..23ecd86 --- /dev/null +++ b/src/analysis/solver.ts @@ -0,0 +1,1033 @@ +import { + ConstraintVar, + IntermediateVar, + NodeVar, + ObjectPropertyVar, + ObjectPropertyVarObj +} from "./constraintvars"; +import logger, {isTTY, writeStdOut} from "../misc/logger"; +import {AccessPathToken, AllocationSiteToken, ArrayToken, FunctionToken, PackageObjectToken, Token} from "./tokens"; +import {AnalysisState} from "./analysisstate"; +import {ModuleInfo, PackageInfo} from "./infos"; +import { + addAll, + isArrayIndex, + mapGetArray, + mapGetMap, + mapGetSet, + mapSetAddAll, + sourceLocationToStringWithFileAndEnd +} from "../misc/util"; +import assert from "assert"; +import { + AccessPath, + CallResultAccessPath, + ComponentAccessPath, + IgnoredAccessPath, + ModuleAccessPath, + PropertyAccessPath, + UnknownAccessPath +} from "./accesspaths"; +import {isAssignmentExpression, Node} from "@babel/types"; +import {FragmentState, ListenerID} from "./fragmentstate"; +import {TokenListener} from "./listeners"; +import {nuutila} from "../misc/scc"; +import {options, patternProperties} from "../options"; +import Timer from "../misc/timer"; +import {setImmediate} from "timers/promises"; +import {AnalysisDiagnostics} from "diagnostics"; +import {getMemoryUsage} from "../misc/memory"; + +export class AbortedException extends Error {} + +export default class Solver { + + readonly analysisState: AnalysisState = new AnalysisState; + + fragmentState: FragmentState = new FragmentState; + + unprocessedTokens: Map> = new Map; + + unprocessedSubsetEdges: Map> = new Map; + + idSymbol = Symbol(); + nextNodeID = 0; + + // TODO: move some of this into AnalysisDiagnostics? + // for diagnostics only + unprocessedTokensSize: number = 0; + unprocessedSubsetEdgesSize: number = 0; + fixpointRound: number = 0; + listenerNotificationRounds: number = 0; + largestTokenSetSize: number = 0; + largestSubsetEdgeOutDegree: number = 0; + lastPrintDiagnosticsTime: number = 0; + tokenListenerNotifications: number = 0; + pairListenerNotifications: number = 0; + packageNeighborListenerNotifications: number = 0; + ancestorListenerNotifications: number = 0; + arrayEntriesListenerNotifications: number = 0; + objectPropertiesListenerNotifications: number = 0; + roundLimitReached: number = 0; + totalCycleEliminationTime = 0; + totalCycleEliminationRuns = 0; + totalPropagationTime = 0; + totalListenerCallTime = 0; + totalWideningTime = 0; + + diagnostics: AnalysisDiagnostics = { + packages: 0, + modules: 0, + functions: 0, + functionToFunctionEdges: 0, + iterations: 0, + uniqueTokens: 0, + aborted: false, + timeout: false, + time: 0, + cpuTime: 0, + codeSize: 0, + maxMemoryUsage: 0 + }; + + readonly abort?: () => boolean; + + fixpointIterationsThrottled: number = 0; + + constructor(abort?: () => boolean) { + this.abort = abort; + } + + updateDiagnostics() { + const a = this.analysisState; + const d = this.diagnostics; + d.functions = a.functionInfos.size; + d.functionToFunctionEdges = a.numberOfFunctionToFunctionEdges; + d.uniqueTokens = a.canonicalTokens.size; + const usage = getMemoryUsage(); + if (logger.isVerboseEnabled()) + logger.verbose(`Memory usage: ${usage}MB`); + d.maxMemoryUsage = Math.max(d.maxMemoryUsage, usage); + } + + /** + * Adds a single token constraint. + */ + addTokenConstraint(t: Token, to: ConstraintVar | undefined) { + if (to === undefined) + return; + if (logger.isDebugEnabled()) // (avoid building message string if not needed) + logger.debug(`Adding constraint ${t} \u2208 ${to}`); + this.addToken(t, this.fragmentState.getRepresentative(to)); + } + + /** + * Enqueues a listener call consisting of a listener and its argument(s). + */ + private enqueueListenerCall(la: [(t: Token) => void, Token] + | [(t1: AllocationSiteToken, t2: FunctionToken) => void, [AllocationSiteToken, FunctionToken]] + | [(neighbor: PackageInfo) => void, PackageInfo] + | [(prop: string) => void, string]) { + this.fragmentState.postponedListenerCalls.push(la); + } + + /** + * Adds a single token if not already present. + * Also enqueues notification of listeners and registers object properties and array entries from the constraint variable. + */ + addToken(t: Token, toRep: ConstraintVar): boolean { + const f = this.fragmentState; + if (f.addToken(t, toRep)) { + f.vars.add(toRep); + this.tokenAdded(toRep, t, + f.subsetEdges.has(toRep), + f.tokenListeners.get(toRep), + f.pairListeners1.get(toRep), + f.pairListeners2.get(toRep)); + // collect statistics + this.updateTokenStats(toRep); + // add object property and array entry if applicable + if (toRep instanceof ObjectPropertyVar) { + this.addObjectProperty(toRep.obj, toRep.prop); + if (toRep.obj instanceof ArrayToken) + this.addArrayEntry(toRep.obj, toRep.prop); + } + return true; + } + return false; + } + + /** + * Adds a set of tokens if not already present. + * By default also adds to worklist and notifies listeners. + */ + addTokens(ts: Iterable, toRep: ConstraintVar, propagate: boolean = true) { + const f = this.fragmentState; + f.vars.add(toRep); + let hasEdges = f.subsetEdges.has(toRep); + let ws: Array | undefined = undefined; + let tr: Map void> | undefined = undefined; + let tr1: Map void]> | undefined = undefined; + let tr2: Map void]> | undefined = undefined; + let any = false; + for (const t of f.addTokens(ts, toRep)) { + any = true; + if (propagate) + ws = this.tokenAdded(toRep, t, hasEdges, + tr ??= f.tokenListeners.get(toRep), + tr1 ??= f.pairListeners1.get(toRep), + tr2 ??= f.pairListeners2.get(toRep), + ws); + } + // add object property and array entry if applicable + if (any && toRep instanceof ObjectPropertyVar) { + this.addObjectProperty(toRep.obj, toRep.prop, propagate); + if (toRep.obj instanceof ArrayToken) + this.addArrayEntry(toRep.obj, toRep.prop, propagate); + } + // collect statistics + this.updateTokenStats(toRep); + } + + private tokenAdded(toRep: ConstraintVar, t: Token, + hasEdges: boolean, + tr: Map void> | undefined, + tr1: Map void]> | undefined, + tr2: Map void]> | undefined, + ws?: Array): Array | undefined { + if (logger.isDebugEnabled()) + logger.debug(`Added token ${t} to ${toRep}`); + const f = this.fragmentState; + // add to worklist if the constraint variable has outgoing subset edges + if (hasEdges) { + (ws ??= mapGetArray(this.unprocessedTokens, toRep)).push(t); + this.unprocessedTokensSize++; + if (this.unprocessedTokensSize % 100 === 0) + this.printDiagnostics(); + } + // notify listeners + if (tr) + for (const listener of tr.values()) { + this.enqueueListenerCall([listener, t]); + this.tokenListenerNotifications++; + } + if (t instanceof AllocationSiteToken && tr1) + for (const [id, [v2, listener]] of tr1) + for (const t2 of f.getTokens(f.getRepresentative(v2))) + if (t2 instanceof FunctionToken) + this.callPairListener(id, listener, t, t2); + if (t instanceof FunctionToken && tr2) + for (const [id, [v1, listener]] of tr2) + for (const t1 of f.getTokens(f.getRepresentative(v1))) + if (t1 instanceof AllocationSiteToken) + this.callPairListener(id, listener, t1, t); + return ws; + } + + /** + * Adds an access path token if not already present (and not at an AssignmentExpression). + * Also collects information for PatternMatcher about where access paths are created. + * @param ap the access path to add + * @param to the AST node (constraint variable) where to add the token (if not an AssignmentExpression) + * @param subap access path of the sub-expression (for call or property access expressions) + */ + addAccessPath(ap: AccessPath, to: ConstraintVar | undefined, subap?: AccessPath) { // TODO: store access paths separately from other tokens? + if (!to) + return; + const abstractProp = ap instanceof PropertyAccessPath && ap.prop !== "default" && patternProperties && !patternProperties.has(ap.prop); + const ap2 = subap instanceof IgnoredAccessPath || (subap instanceof UnknownAccessPath && abstractProp) ? subap : + abstractProp ? this.analysisState.canonicalizeAccessPath(new PropertyAccessPath((ap as PropertyAccessPath).base, "?")) : ap; // abstracting irrelevant access paths + if (logger.isDebugEnabled()) + logger.debug(`Adding access path ${ap2}${ap2 !== ap ? ` (${ap})` : ""} at ${to}${subap ? ` (sub-expression access path: ${subap})` : ""}`); + const a = this.analysisState; + const f = this.fragmentState; + const asn = to instanceof NodeVar && isAssignmentExpression(to.node); + if (!asn) + this.addToken(a.canonicalizeToken(new AccessPathToken(ap2)), f.getRepresentative(to)); + // collect information for PatternMatcher + const t = to instanceof IntermediateVar && to.label === "import" ? to.node : to instanceof NodeVar? to.node : undefined; // special treatment of 'import' expressions + if (t !== undefined) { + if (ap2 instanceof ModuleAccessPath) + mapGetSet(a.moduleAccessPaths, ap2).add(t); + else if (ap2 instanceof PropertyAccessPath) + mapGetMap(mapGetMap(asn ? a.propertyWriteAccessPaths : a.propertyReadAccessPaths, subap!), ap2.prop).set(t, {bp: ap2, sub: ap2.base}); + else if (ap2 instanceof CallResultAccessPath) + mapGetMap(a.callResultAccessPaths, subap!).set(t, {bp: ap2, sub: ap2.caller}); + else if (ap2 instanceof ComponentAccessPath) + mapGetMap(a.componentAccessPaths, subap!).set(t, {bp: ap2, sub: ap2.component}); + else if (!(ap2 instanceof UnknownAccessPath || ap2 instanceof IgnoredAccessPath)) + assert.fail("Unexpected AccessPath"); + } + } + + /** + * Collects statistics after tokens have been added. + */ + private updateTokenStats(toRep: ConstraintVar) { + const [size] = this.fragmentState.getTokensSize(toRep); + if (size > this.largestTokenSetSize) + this.largestTokenSetSize = size; + } + + /** + * Reports diagnostics periodically (only if print progress is enabled, stdout is tty, and log level is "info"). + */ + private printDiagnostics() { + if (options.printProgress && options.tty && isTTY && logger.level === "info") { + const d = new Date().getTime(); + if (d > this.lastPrintDiagnosticsTime + 100) { // only report every 100ms + this.lastPrintDiagnosticsTime = d; + const a = this.analysisState; + const f = this.fragmentState; + writeStdOut(`Packages: ${a.packageInfos.size}, modules: ${a.moduleInfos.size}, call edges: ${a.numberOfFunctionToFunctionEdges}, ` + + (options.diagnostics ? `vars: ${f.getNumberOfVarsWithTokens()}, tokens: ${f.numberOfTokens}, subsets: ${f.numberOfSubsetEdges}, round: ${this.fixpointRound}, ` : "") + + `iterations: ${this.diagnostics.iterations}, worklists: ${this.unprocessedTokensSize}+${this.unprocessedSubsetEdgesSize}` + + (options.diagnostics ? `, listeners: ${f.postponedListenerCalls.length}` : "")); + a.timeoutTimer.checkTimeout(); + } + } + } + + /** + * Adds a subset constraint. + */ + addSubsetConstraint(from: ConstraintVar | undefined, to: ConstraintVar | undefined) { + if (from === undefined || to === undefined) + return; + if (logger.isDebugEnabled()) + logger.debug(`Adding constraint ${from} \u2286 ${to}`); + const f = this.fragmentState; + this.addSubsetEdge(f.getRepresentative(from), f.getRepresentative(to)); + } + + addSubsetEdge(fromRep: ConstraintVar, toRep: ConstraintVar, propagate: boolean = true) { + if (fromRep !== toRep) { + const f = this.fragmentState; + const s = mapGetSet(f.subsetEdges, fromRep); + if (!s.has(toRep)) { + // add the edge + s.add(toRep); + f.numberOfSubsetEdges++; + if (s.size > this.largestSubsetEdgeOutDegree) + this.largestSubsetEdgeOutDegree = s.size; + mapGetSet(f.reverseSubsetEdges, toRep).add(fromRep); + f.vars.add(fromRep); + f.vars.add(toRep); + if (propagate) { + // enqueue propagation of tokens and notification of listeners + mapGetSet(this.unprocessedSubsetEdges, fromRep).add(toRep); + this.unprocessedSubsetEdgesSize++; + } + } + } + } + + /** + * Provides a unique ID for the given key and node. + */ + private getListenerID(key: TokenListener, n: Node): ListenerID { + let id = (n as any)[this.idSymbol] as number | undefined; + if (id === undefined) { + id = this.nextNodeID++; + (n as any)[this.idSymbol] = id; + } + return (id << 10) + key; + } + + /** + * Adds a universally quantified constraint. + * The constraint variable, the key, and the node must together uniquely determine the function. + */ + addForAllConstraint(v: ConstraintVar | undefined, key: TokenListener, n: Node, listener: (t: Token) => void) { + if (v === undefined) + return; + const f = this.fragmentState; + const vRep = f.getRepresentative(v); + if (logger.isDebugEnabled()) + logger.debug(`Adding universally quantified constraint #${TokenListener[key]} to ${vRep} at ${sourceLocationToStringWithFileAndEnd(n.loc)}`); + this.addForAllConstraintPrivate(vRep, this.getListenerID(key, n), listener); + } + + private addForAllConstraintPrivate(vRep: ConstraintVar, id: ListenerID, listener: (t: Token) => void) { + const f = this.fragmentState; + const m = mapGetMap(f.tokenListeners, vRep); + if (!m.has(id)) { + // run listener on all existing tokens + for (const t of f.getTokens(vRep)) { + this.enqueueListenerCall([listener, t]); + this.tokenListenerNotifications++; + } + // register listener for future tokens + m.set(id, listener); + } + } + + /** + * Adds a universally quantified constraint for a pair of constraint variables. + * Only allocation site tokens are considered for the first constraint variable, and only function tokens are considered for the second constraint variable. + * Each constraint variable together with the key and the node must uniquely determine the function and the other constraint variable. + */ + addForAllPairsConstraint(v1: ConstraintVar | undefined, v2: ConstraintVar | undefined, key: TokenListener, n: Node, listener: (t1: AllocationSiteToken, t2: FunctionToken) => void) { + if (v1 === undefined || v2 === undefined) + return; + assert(key !== undefined); + const f = this.fragmentState; + const v1Rep = f.getRepresentative(v1); + const v2Rep = f.getRepresentative(v2); + if (logger.isDebugEnabled()) + logger.debug(`Adding universally quantified pair constraint #${TokenListener[key]} to (${v1Rep}, ${v2Rep}) at ${sourceLocationToStringWithFileAndEnd(n.loc)}`); + this.addForAllPairsConstraintPrivate(v1Rep, v2Rep, this.getListenerID(key, n), listener); + } + + private addForAllPairsConstraintPrivate(v1Rep: ConstraintVar, v2Rep: ConstraintVar, id: ListenerID, listener: (t1: AllocationSiteToken, t2: FunctionToken) => void) { + const f = this.fragmentState; + const m1 = mapGetMap(f.pairListeners1, v1Rep); + if (!m1.has(id)) { + // run listener on all existing tokens + const funs: Array = []; + for (const t2 of f.getTokens(v2Rep)) + if (t2 instanceof FunctionToken) + funs.push(t2); + for (const t1 of f.getTokens(v1Rep)) + if (t1 instanceof AllocationSiteToken) + for (const t2 of funs) + this.callPairListener(id, listener, t1, t2); + // register listener for future tokens + m1.set(id, [v2Rep, listener]); + mapGetMap(f.pairListeners2, v2Rep).set(id, [v1Rep, listener]); + } + } + + /** + * Enqueues a call to a token pair listener if it hasn't been done before. + */ + private callPairListener(id: ListenerID, listener: (t1: AllocationSiteToken, t2: FunctionToken) => void, t1: AllocationSiteToken, t2: FunctionToken) { + const s = mapGetSet(mapGetMap(this.fragmentState.pairListenersProcessed, id), t1); + if (!s.has(t2)) { + s.add(t2); + this.enqueueListenerCall([listener, [t1, t2]]); + this.pairListenerNotifications++; + } + } + + /** + * Adds a quantified constraint for all neighbors of the given package. + * The PackageInfo and the node must together uniquely determine the function. + */ + addForAllPackageNeighborsConstraint(k: PackageInfo, n: Node, listener: (neighbor: PackageInfo) => void) { + if (logger.isDebugEnabled()) + logger.debug(`Adding package neighbor constraint to ${k}`); + this.addForAllPackageNeighborsConstraintPrivate(k, n, listener); + } + + private addForAllPackageNeighborsConstraintPrivate(k: PackageInfo, n: Node, listener: (neighbor: PackageInfo) => void) { + const f = this.fragmentState; + const m = mapGetMap(f.packageNeighborListeners, k); + if (!m.has(n)) { + // run listener on all existing neighbors + const ns = f.packageNeighbors.get(k); + if (ns) + for (const n of ns) { + this.enqueueListenerCall([listener, n]); + this.packageNeighborListenerNotifications++; + } + // register listener for future neighbors + m.set(n, listener); + } + } + + /** + * Adds a package neighbor relation. + * By default also notifies listeners. + */ + addPackageNeighbor(k1: PackageInfo, k2: PackageInfo, propagate: boolean = true) { + this.addPackageNeighborPrivate(k1, k2, propagate); + this.addPackageNeighborPrivate(k2, k1, propagate); + } + + private addPackageNeighborPrivate(k: PackageInfo, neighbor: PackageInfo, propagate: boolean = true) { + const f = this.fragmentState; + const s = mapGetSet(f.packageNeighbors, k); + if (!s.has(neighbor)) { + s.add(neighbor); + if (propagate) { + const ts = f.packageNeighborListeners.get(k); + if (ts) + for (const listener of ts.values()) { + this.enqueueListenerCall([listener, neighbor]); + this.packageNeighborListenerNotifications++; + } + } + } + } + + /** + * Adds a quantified constraint for all ancestors (reflexive and transitive) of the given token. + * The token and the node must together uniquely determine the function. + */ + addForAllAncestorsConstraint(t: Token, n: Node, listener: (ancestor: Token) => void) { + if (logger.isDebugEnabled()) + logger.debug(`Adding ancestors constraint to ${t}`); + this.addForAllAncestorsConstraintPrivate(t, n, listener); + } + + private addForAllAncestorsConstraintPrivate(t: Token, n: Node, listener: (ancestor: Token) => void) { + const f = this.fragmentState; + const m = mapGetMap(f.ancestorListeners, t); + if (!m.has(n)) { + // run listener on all existing ancestors + for (const a of f.getAncestors(t)) { + const p = mapGetSet(f.ancestorListenersProcessed, n); + if (!p.has(a)) { + this.enqueueListenerCall([listener, a]); + this.ancestorListenerNotifications++; + mapGetSet(f.ancestorListenersProcessed, n).add(a); + } + } + // register listener for future inheritance relations + m.set(n, listener); + } + } + + /** + * Adds an inheritance relation. + * By default also notifies listeners. + */ + addInherits(child: Token, parent: Token, propagate: boolean = true) { + if (child === parent) + return; + const f = this.fragmentState; + const st = mapGetSet(f.inherits, child); + if (!st.has(parent)) { + if (logger.isDebugEnabled()) + logger.debug(`Adding inheritance relation ${child} -> ${parent}`); + st.add(parent); + mapGetSet(f.reverseInherits, parent).add(child); + if (propagate) { + for (const des of f.getDescendants(child)) { + const ts = f.ancestorListeners.get(des); + if (ts) + for (const anc of f.getAncestors(parent)) + for (const [n, listener] of ts) { + const p = mapGetSet(f.ancestorListenersProcessed, n); + if (!p.has(anc)) { + this.enqueueListenerCall([listener, anc]); + this.ancestorListenerNotifications++; + p.add(anc); + } + } + } + } + } + } + + /** + * Adds a quantified constraint for all explicit numeric properties of the given array. + */ + addForAllArrayEntriesConstraint(t: ArrayToken, key: TokenListener, n: Node, listener: (prop: string) => void) { + if (logger.isDebugEnabled()) + logger.debug(`Adding array entries constraint #${TokenListener[key]} to ${t} at ${sourceLocationToStringWithFileAndEnd(n.loc)}`); + this.addForAllArrayEntriesConstraintPrivate(t, this.getListenerID(key, n), listener); + } + + private addForAllArrayEntriesConstraintPrivate(t: ArrayToken, id: ListenerID, listener: (prop: string) => void) { + const f = this.fragmentState; + const m = mapGetMap(f.arrayEntriesListeners, t); + if (!m.has(id)) { + // run listener on all existing entries + const ps = f.arrayEntries.get(t); + if (ps) + for (const p of ps) { + this.enqueueListenerCall([listener, p]); + this.arrayEntriesListenerNotifications++; + } + // register listener for future entries + m.set(id, listener); + } + } + + /** + * Adds an array numeric property and notifies listeners. + * Non-numeric properties are ignored. + * By default also notifies listeners. + */ + addArrayEntry(a: ArrayToken, prop: string, propagate: boolean = true) { + if (!isArrayIndex(prop)) // TODO: treat large indices as "unknown"? + return; + const f = this.fragmentState; + const ps = mapGetSet(f.arrayEntries, a); + if (!ps.has(prop)) { + if (logger.isDebugEnabled()) + logger.debug(`Adding array entry ${a}[${prop}]`); + ps.add(prop); + if (propagate) { + const ts = f.arrayEntriesListeners.get(a); + if (ts) + for (const listener of ts.values()) { + this.enqueueListenerCall([listener, prop]); + this.arrayEntriesListenerNotifications++; + } + } + } + } + + /** + * Adds a quantified constraint for all properties of the given object. + */ + addForAllObjectPropertiesConstraint(t: ObjectPropertyVarObj, key: TokenListener, n: Node, listener: (prop: string) => void) { + if (logger.isDebugEnabled()) + logger.debug(`Adding object properties constraint #${TokenListener[key]} to ${t} at ${sourceLocationToStringWithFileAndEnd(n.loc)}`); + this.addForAllObjectPropertiesConstraintPrivate(t, this.getListenerID(key, n), listener); + } + + private addForAllObjectPropertiesConstraintPrivate(t: ObjectPropertyVarObj, id: ListenerID, listener: (prop: string) => void) { + const f = this.fragmentState; + const m = mapGetMap(f.objectPropertiesListeners, t); + if (!m.has(id)) { + // run listener on all existing properties + const ps = f.objectProperties.get(t); + if (ps) + for (const p of ps) { + this.enqueueListenerCall([listener, p]); + this.objectPropertiesListenerNotifications++; + } + // register listener for future properties + m.set(id, listener); + } + } + + /** + * Adds an object property and notifies listeners. + * By default also notifies listeners. + */ + addObjectProperty(a: ObjectPropertyVarObj, prop: string, propagate: boolean = true) { + const f = this.fragmentState; + const ps = mapGetSet(f.objectProperties, a); + if (!ps.has(prop)) { + if (logger.isDebugEnabled()) + logger.debug(`Adding object property ${a}.${prop}`); + ps.add(prop); + if (propagate) { + const ts = f.objectPropertiesListeners.get(a); + if (ts) + for (const listener of ts.values()) { + this.enqueueListenerCall([listener, prop]); + this.objectPropertiesListenerNotifications++; + } + } + } + } + + /** + * Collects property read operations. + * @param result the constraint variable for the result of the property read operation + * @param base the constraint variable for the base expression + * @param pck the current package object token + */ + collectPropertyRead(result: ConstraintVar | undefined, base: ConstraintVar | undefined, pck: PackageObjectToken) { + if (result && base) + this.analysisState.maybeEmptyPropertyReads.push({result, base, pck}); + } + + /** + * Collects dynamic property write operations. + * @param base the constraint variable for the base expression + */ + collectDynamicPropertyWrite(base: ConstraintVar | undefined) { + if (base) + this.analysisState.dynamicPropertyWrites.add(base); + } + + /** + * Redirects constraint variable. + * Updates the subset edges and listeners, and propagates worklist tokens along redirected edges. + * Assumes that there is a subset path from v to rep. + * @param v constraint variable to redirect + * @param rep new representative (possibly v itself if v previously had another representative) + */ + redirect(v: ConstraintVar, rep: ConstraintVar) { + const f = this.fragmentState; + assert(f.vars.has(v)); + const oldRep = f.getRepresentative(v); + if (oldRep === rep) { + // v is already represented by rep + return; + } + if (logger.isDebugEnabled()) + logger.debug(`Redirecting ${v} to ${rep}`); + if (oldRep !== v) { + // v is already redirected, so it shouldn't have any subset edges, listeners or tokens + assert(!f.subsetEdges.has(v)); + assert(!f.reverseSubsetEdges.has(v)); + assert(!f.tokenListeners.has(v)); + assert(!f.pairListeners1.has(v)); + assert(!f.pairListeners2.has(v)); + assert(!f.hasVar(v)); + assert(!this.unprocessedTokens.has(v)); + assert(!this.unprocessedSubsetEdges.has(v)); // also holds for reverse unprocessedSubsetEdges but too costly to assert + } + if (v === rep) { + // v now becomes its own representative, and oldRep !== rep === v so the assertions above apply + f.redirections.delete(v); + f.vars.add(v); + } else { + // set rep as new representative for v + f.redirections.set(v, rep); + if (oldRep === v) { // if v was already redirected, then the assertions above apply + // process v's new outgoing subset edges + const ws = this.unprocessedSubsetEdges.get(v); + if (ws) { + for (const w of ws) + this.processEdge(v, w); + this.unprocessedSubsetEdges.delete(v); + } + // propagate worklist tokens (assuming there is a subset path from v to rep) + this.processTokens(v); + const [size, has] = this.fragmentState.getSizeAndHas(v); + this.fragmentState.deleteVar(v); + f.numberOfTokens -= size; + // redirect subset edges + const repOut = mapGetSet(f.subsetEdges, rep); + const repIn = mapGetSet(f.reverseSubsetEdges, rep); + const vOut = f.subsetEdges.get(v); + if (vOut) { + for (const w of vOut) { + if (w !== rep) { + const qs = f.reverseSubsetEdges.get(w); + assert(qs, "Subset edges empty"); + qs.delete(v); + if (!repOut.has(w)) { + repOut.add(w); + qs.add(rep); + f.numberOfSubsetEdges++; + } + } + } + f.numberOfSubsetEdges -= vOut.size; + f.subsetEdges.delete(v); + } + const vIn = f.reverseSubsetEdges.get(v); + if (vIn) { + for (const w of vIn) + if (w !== rep) { + const qs = f.subsetEdges.get(w); + assert(qs, "Subset edges empty"); + qs.delete(v); + if (!repIn.has(w)) { + repIn.add(w); + qs.add(rep); + f.numberOfSubsetEdges++; + } + } + f.numberOfSubsetEdges -= vIn.size; + f.reverseSubsetEdges.delete(v); + } + repOut.delete(v); + repIn.delete(v); + if (repOut.size === 0) + f.subsetEdges.delete(rep); + if (repIn.size === 0) + f.reverseSubsetEdges.delete(rep); + // redirect listeners, invoke on existing tokens in rep that are not in v + const rts: Set = new Set; + for (const t of f.getTokens(rep)) + if (!has(t)) + rts.add(t); + const tr = f.tokenListeners.get(v); + if (tr) { + const qr = mapGetMap(f.tokenListeners, rep); + for (const [k, listener] of tr) { + qr.set(k, listener); + for (const t of rts) { + this.enqueueListenerCall([listener, t]); + this.tokenListenerNotifications++; + } + } + f.tokenListeners.delete(v); + } + const tr1 = f.pairListeners1.get(v); + if (tr1) { + const bases: Array = []; + for (const t of rts) + if (t instanceof AllocationSiteToken) + bases.push(t); + const qr1 = mapGetMap(f.pairListeners1, rep) + for (const [k, v2l] of tr1) { + qr1.set(k, v2l); + const [v2, listener] = v2l; + for (const t2 of f.getTokens(v2)) + if (t2 instanceof FunctionToken) + for (const t of bases) + this.callPairListener(k, listener, t, t2); + } + f.pairListeners1.delete(v); + } + const tr2 = f.pairListeners2.get(v); + if (tr2) { + const funs: Array = []; + for (const t of rts) + if (t instanceof FunctionToken) + funs.push(t); + const qr2 = mapGetMap(f.pairListeners2, rep) + for (const [k, v1l] of tr2) { + qr2.set(k, v1l); + const [v1, listener] = v1l; + for (const t1 of f.getTokens(v1)) + if (t1 instanceof AllocationSiteToken) + for (const t of funs) + this.callPairListener(k, listener, t1, t); + } + f.pairListeners2.delete(v); + } + f.vars.delete(v); + f.vars.add(rep); + } + } + } + + /** + * Processes the items in the token worklist for the given constraint variable. + */ + processTokens(v: ConstraintVar) { + const ts = this.unprocessedTokens.get(v); + if (ts) { + if (logger.isDebugEnabled()) + logger.debug(`Worklist sizes: ${this.unprocessedTokensSize}+${this.unprocessedSubsetEdgesSize}, propagating ${ts.length} token${ts.length !== 1 ? "s" : ""} from ${v}`); + this.unprocessedTokens.delete(v); + this.unprocessedTokensSize -= ts.length; + // propagate new tokens to successors + const f = this.fragmentState; + assert(f.vars.has(v)); + let s = f.subsetEdges.get(v); + if (s) + for (const to of s) + this.addTokens(ts, to); + this.incrementFixpointIterations(); + } + } + + /** + * Propagates tokens along a new subset edge. + */ + processEdge(fromRep: ConstraintVar, to: ConstraintVar) { + const f = this.fragmentState; + const toRep = f.getRepresentative(to); + const [size, ts] = this.fragmentState.getTokensSize(fromRep); + if (size > 0) { + if (logger.isDebugEnabled()) + logger.debug(`Worklist sizes: ${this.unprocessedTokensSize}+${this.unprocessedSubsetEdgesSize}, propagating ${size} token${size !== 1 ? "s" : ""} from ${fromRep}`); + this.addTokens(ts, toRep); + this.incrementFixpointIterations(); + } + this.unprocessedSubsetEdgesSize--; + } + + incrementFixpointIterations() { + this.diagnostics.iterations++; + if (this.diagnostics.iterations % 100 === 0) { + this.analysisState.timeoutTimer.checkTimeout(); + this.printDiagnostics(); + } + } + + /** + * Processes all items in the worklist until a fixpoint is reached. + * This notifies listeners and propagates tokens along subset edges. + */ + async propagate() { + if (logger.isDebugEnabled()) + logger.debug("Processing constraints until fixpoint..."); + const a = this.analysisState; + const f = this.fragmentState; + a.timeoutTimer.checkTimeout(); + await this.checkAbort(); + let round = 0; + while (this.unprocessedTokens.size > 0 || this.unprocessedSubsetEdges.size > 0 || f.postponedListenerCalls.length > 0) { + round++; + this.fixpointRound = round; + if (logger.isVerboseEnabled()) + logger.verbose(`Fixpoint round: ${round} (call edges: ${a.numberOfFunctionToFunctionEdges}, vars: ${f.getNumberOfVarsWithTokens()}, tokens: ${f.numberOfTokens}, subsets: ${f.numberOfSubsetEdges})`); + if (options.maxRounds !== undefined && round > options.maxRounds) { + a.warn(`Fixpoint round limit reached, aborting propagation`); + this.roundLimitReached++; + this.unprocessedTokensSize = 0; + this.unprocessedTokens.clear(); + this.unprocessedSubsetEdgesSize = 0; + this.unprocessedSubsetEdges.clear(); + f.postponedListenerCalls.length = 0; + break; + } + if (this.unprocessedTokens.size > 0 || this.unprocessedSubsetEdges.size > 0) { + if (options.cycleElimination) { + // find vars that are end points of new subset edges + const nodes = new Set(); + for (const [v, ws] of this.unprocessedSubsetEdges) { + nodes.add(v); + for (const w of ws) + nodes.add(w); + } + // find strongly connected components + const timer1 = new Timer(); + const [reps, repmap] = nuutila(nodes, (v: ConstraintVar) => f.subsetEdges.get(v) || []); + if (logger.isVerboseEnabled()) + logger.verbose(`Cycle detection nodes: ${f.vars.size}, components: ${reps.length}`); + // cycle elimination + for (const [v, rep] of repmap) + this.redirect(v, rep); // TODO: this includes processing pending edges and tokens for v, which may be unnecessary? + this.totalCycleEliminationTime += timer1.elapsedCPU(); + this.totalCycleEliminationRuns++; + // TODO: (transitive reduction:) mark subset edges a->b as "ignored" if there is another path a==>c==>b? then skip those edges when new tokens appear in a (represent ignored edges separately, only look at ignored edges when adding new edges) - detect during cycle detection? + const timer2 = new Timer(); + // process new tokens and subset edges for the component representatives in topological order + for (let i = reps.length - 1; i >= 0; i--) { + const v = reps[i]; + const ws = this.unprocessedSubsetEdges.get(v); + if (ws) + for (const w of ws) + this.processEdge(v, w); + this.processTokens(v); + await this.checkAbort(true); + } + this.unprocessedSubsetEdges.clear(); + // process remaining tokens outside the sub-graph reachable via the new edges + for (const v of this.unprocessedTokens.keys()) + this.processTokens(v); + this.totalPropagationTime += timer2.elapsedCPU(); + } else { + // process all constraint variables and subset edges in worklists until empty + const timer = new Timer(); + for (const [v, ws] of this.unprocessedSubsetEdges) + for (const w of ws) { + this.processEdge(v, w); + await this.checkAbort(true); + } + this.unprocessedSubsetEdges.clear(); + for (const v of this.unprocessedTokens.keys()) { + this.processTokens(v); + await this.checkAbort(true); + } + this.totalPropagationTime += timer.elapsedCPU(); + } + } + if (this.unprocessedTokens.size !== 0 || this.unprocessedTokensSize !== 0 || this.unprocessedSubsetEdges.size !== 0 || this.unprocessedSubsetEdgesSize !== 0) + assert.fail(`worklist non-empty: unprocessedTokens.size: ${this.unprocessedTokens.size}, unprocessedTokensSize: ${this.unprocessedTokensSize}, unprocessedSubsetEdges.size: ${this.unprocessedSubsetEdges.size}, unprocessedSubsetEdgesSize: ${this.unprocessedSubsetEdgesSize}`); + // process all enqueued listener calls (excluding those created during the processing) + if (logger.isVerboseEnabled()) + logger.verbose(`Processing listener calls: ${f.postponedListenerCalls.length}`); + if (f.postponedListenerCalls.length > 0) { + const timer = new Timer(); + this.listenerNotificationRounds++; + const calls = Array.from(f.postponedListenerCalls); + f.postponedListenerCalls.length = 0; + let count = 0; + for (const [fun, args] of calls) { + (fun as Function).apply(undefined, Array.isArray(args) ? args : [args]); + if (++count % 100 === 0) { + a.timeoutTimer.checkTimeout(); + this.printDiagnostics(); + } + } + this.totalListenerCallTime += timer.elapsedCPU(); + } + } + if (this.unprocessedTokensSize !== 0) + assert.fail(`unprocessedTokensSize non-zero after propagate: ${this.unprocessedTokensSize}`); + if (this.unprocessedSubsetEdgesSize !== 0) + assert.fail(`unprocessedSubsetEdgesSize non-zero after propagate: ${this.unprocessedSubsetEdgesSize}`); + if (f.postponedListenerCalls.length > 0) + assert.fail(`postponedListenerCalls non-empty after propagate: ${f.postponedListenerCalls.length}`); + } + + async checkAbort(throttle: boolean = false) { + if (this.abort) { + if (throttle) { + if (this.diagnostics.iterations < this.fixpointIterationsThrottled + 1000) + return; + this.fixpointIterationsThrottled = this.diagnostics.iterations; + } + await setImmediate(); // gives the server a chance to process abort requests + if (this.abort()) { + logger.verbose("Abort signal received"); + throw new AbortedException(); + } + } + } + + /** + * Initializes a new fragment state. + */ + prepare() { + this.fragmentState = new FragmentState(); + } + + /** + * Stores the fragment state in the given module or package. + */ + store(mp: ModuleInfo | PackageInfo) { + if (logger.isDebugEnabled()) + logger.debug(`Storing state for ${mp}`); + mp.fragmentState = this.fragmentState; + } + + /** + * Restores the fragment state for the module or package. + */ + restore(mp: ModuleInfo | PackageInfo, propagate: boolean = true) { // TODO: reconsider use of 'propagate' flag + const s = mp.fragmentState; + if (s) { + if (logger.isDebugEnabled()) + logger.debug(`Restoring state for ${mp}`); + const f = this.fragmentState; + // represent redirections as two-way subset edges, but only if using cycle elimination + if (options.cycleElimination) + for (const [v, rep] of s.redirections) { // Note: because redirections are restored like this and no final cycle elimination is performed, listeners may re-add tokens and subset edges differently depending on choices of SCC representatives + mapGetSet(s.subsetEdges, v).add(rep); + mapGetSet(s.reverseSubsetEdges, rep).add(v); + mapGetSet(s.subsetEdges, rep).add(v); + mapGetSet(s.reverseSubsetEdges, v).add(rep); + } + // copy fragment state + addAll(s.vars, f.vars); + mapSetAddAll(s.ancestorListenersProcessed, f.ancestorListenersProcessed); + for (const [id, m] of s.pairListenersProcessed) + mapSetAddAll(m, mapGetMap(f.pairListenersProcessed, id)); + for (const [v, m] of s.tokenListeners) { + const vRep = f.getRepresentative(v); + for (const [id, listener] of m) + this.addForAllConstraintPrivate(vRep, id, listener); + } + for (const [v1, m] of s.pairListeners1) { + const v1Rep = f.getRepresentative(v1); + for (const [id, [v2, listener]] of m) + this.addForAllPairsConstraintPrivate(v1Rep, f.getRepresentative(v2), id, listener); + } + for (const [k, m] of s.packageNeighborListeners) + for (const [n, listener] of m) + this.addForAllPackageNeighborsConstraintPrivate(k, n, listener); + for (const [t, m] of s.ancestorListeners) + for (const [n, listener] of m) + this.addForAllAncestorsConstraintPrivate(t, n, listener); + for (const [t, m] of s.arrayEntriesListeners) + for (const [id, listener] of m) + this.addForAllArrayEntriesConstraintPrivate(t, id, listener); + for (const [t, m] of s.objectPropertiesListeners) + for (const [id, listener] of m) + this.addForAllObjectPropertiesConstraintPrivate(t, id, listener); + for (const [v, ts] of s.getAllVarsAndTokens()) + this.addTokens(ts, f.getRepresentative(v), propagate); + for (const [v, ws] of s.subsetEdges) { + const vRep = f.getRepresentative(v); + for (const w of ws) + this.addSubsetEdge(vRep, f.getRepresentative(w), propagate); + } + for (const [c, ps] of s.inherits) + for (const p of ps) + this.addInherits(c, p, propagate); + for (const [k, ns] of s.packageNeighbors) + for (const n of ns) + this.addPackageNeighbor(k, n, propagate); + this.printDiagnostics(); + } else if (logger.isVerboseEnabled()) + logger.verbose(`No state found for ${mp}`); + } +} \ No newline at end of file diff --git a/src/analysis/tokens.ts b/src/analysis/tokens.ts new file mode 100644 index 0000000..5b75ab0 --- /dev/null +++ b/src/analysis/tokens.ts @@ -0,0 +1,166 @@ +import {Function, Node} from "@babel/types"; +import {sourceLocationToStringWithFileAndEnd} from "../misc/util"; +import assert from "assert"; +import {ModuleInfo, PackageInfo} from "./infos"; +import {AccessPath} from "./accesspaths"; +import {NativeFunctionAnalyzer} from "../natives/nativebuilder"; + +/** + * Abstract value for constraint variables. + */ +export abstract class Token { + + abstract toString(): string; +} + +/** + * Token that represents function objects. + */ +export class FunctionToken extends Token { + + fun: Function; + + moduleInfo: ModuleInfo; + + constructor(fun: Function, moduleInfo: ModuleInfo) { + super(); + this.fun = fun; + this.moduleInfo = moduleInfo; + } + + toString() { + return `Function[${sourceLocationToStringWithFileAndEnd(this.fun.loc)}]`; + } +} + +/** + * Object kinds, used by AllocationSiteToken and PackageObjectToken. + * + * Iterator represents an abstraction of Iterator, Iterable, IterableIterator, IteratorResult, Generator and AsyncGenerator + * (thus conflating the different kinds of objects). + * It has a property 'value' holding the iterator values and a method 'next' that returns the abstract object itself. + * + * PromiseResolve and PromiseReject represent the resolve and reject function arguments of promise executors, + * using the same allocation site as the promise they belong to. + */ +export type ObjectKind = "Object" | "Array" | "Class" | "Map" | "Set" | "WeakMap" | "WeakSet" | "WeakRef" | "Iterator" | "RegExp" | "Date" | "Promise" | "PromiseResolve" | "PromiseReject"; + +/** + * Token that represents objects with a specific allocation site. + */ +export class AllocationSiteToken extends Token { + + kind: ObjectKind; + + allocSite: Node; + + packageInfo: PackageInfo; + + constructor(kind: ObjectKind, allocSite: Node, packageInfo: PackageInfo) { + super(); + this.kind = kind; + this.allocSite = allocSite; + this.packageInfo = packageInfo; + assert(this instanceof ArrayToken || kind !== "Array", "AllocationSiteTokens of kind Array must be created using ArrayToken"); + assert(this instanceof ObjectToken || kind !== "Object", "AllocationSiteTokens of kind Object must be created using ObjectToken"); + assert(this instanceof ClassToken || kind !== "Class", "AllocationSiteTokens of kind Class must be created using ClassToken"); + } + + toString() { + return `${this.kind}[${sourceLocationToStringWithFileAndEnd(this.allocSite.loc)}]`; + } +} + +/** + * Token that represents ordinary objects with a specific allocation site. + */ +export class ObjectToken extends AllocationSiteToken { + + constructor(allocSite: Node, packageInfo: PackageInfo) { + super("Object", allocSite, packageInfo); + } +} + +/** + * Token that represents arrays with a specific allocation site. + */ +export class ArrayToken extends AllocationSiteToken { + + constructor(allocSite: Node, packageInfo: PackageInfo) { + super("Array", allocSite, packageInfo); + } +} + +/** + * Token that represents classes with a specific allocation site. + */ +export class ClassToken extends AllocationSiteToken { + + constructor(allocSite: Node, packageInfo: PackageInfo) { + super("Class", allocSite, packageInfo); + } +} + +/** + * Token that represents a native object. + */ +export class NativeObjectToken extends Token { + + readonly name: string; + + readonly moduleInfo: ModuleInfo | undefined; + + readonly invoke: NativeFunctionAnalyzer | undefined; + + readonly constr: boolean; + + constructor(name: string, moduleInfo?: ModuleInfo, invoke?: NativeFunctionAnalyzer, constr: boolean = false) { + super(); + this.name = name; + this.moduleInfo = moduleInfo; + this.invoke = invoke; + this.constr = constr; + } + + toString() { + return `%${this.name}${this.moduleInfo ? `[${this.moduleInfo}]` : ""}`; + } +} + +/** + * Token that represents unknown values belonging to a specific package. + */ +export class PackageObjectToken extends Token { + + kind: ObjectKind; + + readonly packageInfo: PackageInfo; + + constructor(packageInfo: PackageInfo, kind: ObjectKind = "Object") { + super(); + this.kind = kind; + this.packageInfo = packageInfo; + } + + toString() { + return `*${this.kind === "Object" ? "" : `(${this.kind})`}[${this.packageInfo}]` + } +} + +/** + * Token that describes values that come from non-analyzed code (either libraries or clients). + * In vulnerability pattern matching mode, access path tokens are used for values from tracked modules. + */ +export class AccessPathToken extends Token { + + readonly ap: AccessPath; + + constructor(ap: AccessPath) { + super(); + this.ap = ap; + } + + toString(): string { + return `@${this.ap}`; + } +} diff --git a/src/analysis/widening.ts b/src/analysis/widening.ts new file mode 100644 index 0000000..933c36b --- /dev/null +++ b/src/analysis/widening.ts @@ -0,0 +1,172 @@ +import Solver from "./solver"; +import {ObjectToken, PackageObjectToken, Token} from "./tokens"; +import logger from "../misc/logger"; +import {ConstraintVar, ObjectPropertyVar} from "./constraintvars"; +import {addAll, getOrSet, mapGetSet} from "../misc/util"; +import {ModuleInfo} from "./infos"; +import Timer from "../misc/timer"; +import {CallResultAccessPath, ComponentAccessPath, PropertyAccessPath} from "./accesspaths"; +import assert from "assert"; + +// TODO: OK to assume that all tokens in widened belong to the current fragment? +// TODO: measure effect of widening... + +/** + * Widens the selected objects from allocation-site to package abstraction. + * This roughly takes time proportional to the size of the information stored for the constraint variables and tokens. + */ +export function widenObjects(m: ModuleInfo, widened: Set, solver: Solver) { + const a = solver.analysisState; + const f = solver.fragmentState; + if (logger.isVerboseEnabled()) + logger.verbose(`Widening (constraint vars: ${f.getNumberOfVarsWithTokens()}, widened tokens: ${widened.size})`); + if (logger.isDebugEnabled()) + for (const t of widened) + logger.debug(`Widening ${t}`); + if (widened.size === 0) + return; + addAll(widened, a.widened); + const timer = new Timer; + + const tokenMap: Map = new Map; + for (const t of widened) + tokenMap.set(t, a.canonicalizeToken(new PackageObjectToken(t.packageInfo))); + + /** + * Returns the widened version of the given token, or the given token itself if it is not being widened. + */ + function widenToken(t: T): T | PackageObjectToken { + return tokenMap.get(t as any) ?? t; + } + + function widenTokenSet(ts: Iterable): Set { + const res: Set = new Set; + for (const t of ts) + res.add(widenToken(t)); + return res; + } + + function widenTokenMapArrayValues(m: Map>): [Map>, number] { + const res: Map> = new Map; + let size = 0; + for (const [v, ts] of m) { + const s = widenTokenSet(ts); + res.set(v, Array.from(s)); + size += s.size; + } + return [res, size]; + } + + function widenTokenMapSetKeys(m: Map>): Map> { + const res: Map> = new Map; + for (const [t, vs] of m) + addAll(vs, mapGetSet(m, widenToken(t))); + return res; + } + + function widenTokenMapSetKeysValues(m: Map>): Map> { + const res: Map> = new Map; + for (const [v, qs] of m) { + const ws = mapGetSet(res, widenToken(v)); + for (const q of qs) + ws.add(widenToken(q)); + } + return res; + } + + function widenTokenMapKeys(m: Map): Map { + const res: Map = new Map; + for (const [t, v] of m) + res.set(widenToken(t), v); // possibly overriding existing different value, but should be a listener function with same behavior + return res; + } + + const varMap: Map = new Map; // cache for widenVar + + /** + * Returns the widened version of the given constraint variable, or the constraint variable itself if it is not being widened. + */ + function widenVar(v: ConstraintVar): ConstraintVar { + if (v instanceof ObjectPropertyVar && v.obj instanceof ObjectToken && widened.has(v.obj)) { + const vobj = v.obj; + return getOrSet(varMap, v, () => a.varProducer.packagePropVar(vobj.packageInfo, v.prop, v.accessor)); + } else + return v; + } + + function widenVarSet(s: Set): Set { + const res: Set = new Set; + for (const v of s) + res.add(widenVar(v)); + return res; + } + + function widenPropertyAccessPath(ap: PropertyAccessPath): PropertyAccessPath { + const w = widenVar(ap.base); + if (w === ap.base) + return ap; + return a.canonicalizeAccessPath(new PropertyAccessPath(w, ap.prop)); + } + + function widenCallResultAccessPath(ap: CallResultAccessPath): CallResultAccessPath { + const w = widenVar(ap.caller); + if (w === ap.caller) + return ap; + return a.canonicalizeAccessPath(new CallResultAccessPath(w)); + + } + + function widenComponentAccessPath(ap: ComponentAccessPath): ComponentAccessPath { + const w = widenVar(ap.component); + if (w === ap.component) + return ap; + return a.canonicalizeAccessPath(new ComponentAccessPath(w)); + + } + + // update the tokens + [solver.unprocessedTokens, solver.unprocessedTokensSize] = widenTokenMapArrayValues(solver.unprocessedTokens); + assert(solver.unprocessedSubsetEdges.size === 0 && solver.unprocessedSubsetEdgesSize === 0); + f.replaceTokens(widenTokenSet); + f.inherits = widenTokenMapSetKeysValues(f.inherits); + f.reverseInherits = widenTokenMapSetKeysValues(f.reverseInherits); + f.ancestorListeners = widenTokenMapKeys(f.ancestorListeners); // FIXME: if a token gets a new ancestor because of widening, ancestor listeners may need to be invoked? + f.objectPropertiesListeners = widenTokenMapKeys(f.objectPropertiesListeners); // FIXME: if an ObjectPropertyVarObj token gets a new property because of widening, object properties listeners may need to be invoked? + f.objectProperties = widenTokenMapSetKeys(f.objectProperties); + + // update the constraint variables + for (const v of f.vars) { + const rep = f.getRepresentative(widenVar(v)); + solver.addSubsetEdge(v, rep); // ensures that tokens get transferred + solver.redirect(v, rep); + } + a.dynamicPropertyWrites = widenVarSet(a.dynamicPropertyWrites); + for (const e of a.maybeEmptyPropertyReads) { + e.result = widenVar(e.result); + e.base = widenVar(e.base); + } + for (const e of a.unhandledDynamicPropertyWrites.values()) + e.src = widenVar(e.src); + for (const m of [a.propertyReadAccessPaths, a.propertyWriteAccessPaths]) + for (const m1 of m.values()) + for (const m2 of m1.values()) + for (const e of m2.values()) { + e.sub = widenVar(e.sub); + e.bp = widenPropertyAccessPath(e.bp); + } + for (const m of a.callResultAccessPaths.values()) + for (const e of m.values()) { + e.sub = widenVar(e.sub); + e.bp = widenCallResultAccessPath(e.bp); + } + for (const m of a.componentAccessPaths.values()) + for (const e of m.values()) { + e.sub = widenVar(e.sub); + e.bp = widenComponentAccessPath(e.bp); + } + + const ms = timer.elapsed(); + solver.totalWideningTime += ms; + if (logger.isVerboseEnabled()) + logger.verbose(`Widening completed in ${ms}ms`); +} diff --git a/src/dynamic/dyn.ts b/src/dynamic/dyn.ts new file mode 100644 index 0000000..2ebf937 --- /dev/null +++ b/src/dynamic/dyn.ts @@ -0,0 +1,342 @@ +/*! DO NOT INSTRUMENT */ + +/** + * Packages that are typically used for tests only and should be excluded in the collected call graphs. + */ +const TEST_PACKAGES = ["yarn", "mocha", "chai", "nyc", "sinon", "should", "@babel", "jest"]; // TODO: other test packages? + +/** + * Commands that do not need instrumentation, for example because the actual work is known to happen in child processes. + */ +const IGNORED_COMMANDS = ["npm", "npm-cli.js", "eslint", "grunt", "tsc", "tsd", "prettier", "rimraf", "xo"]; // TODO: other commands where instrumentation can be skipped? + +// override 'node' executable by overwriting process.execPath and prepending $JELLY_BIN to $PATH +const jellybin = process.env.JELLY_BIN; +const node = `${jellybin}/node`; +if (!jellybin) { + console.error('Error: Environment variable JELLY_BIN not set, aborting'); + process.exit(-1); +} +process.execPath = node; +const child_process = require('child_process'); +for (const fun of ["spawn", "spawnSync"]) { + const real = child_process[fun]; + child_process[fun] = function() { + const env = arguments[2]?.env || process.env; + const opts = + { ...arguments[2], + env: {...env, + PATH: `${jellybin}${env.PATH ? `:${env.PATH}` : ""}`, + NODE: node, + npm_node_execpath: node + }}; + // console.log("jelly:", fun, arguments[0], arguments[1].join(" ")/*, opts*/); // XXX + return real.call(this, arguments[0], arguments[1], opts); + }; +} + +// skip instrumentation of selected commands where actual work is known to happen in child processes +const cmd = process.argv[4]; +for (const s of IGNORED_COMMANDS) + if (cmd.endsWith(`/${s}`)) { + console.log(`jelly: Skipping instrumentation of ${cmd}`); + // @ts-ignore + return; + } + +const outfile = process.env.JELLY_OUT + "-" + process.pid; +if (!outfile) { + console.error('Error: Environment variable JELLY_OUT not set, aborting'); + process.exit(-1); +} + +console.log(`jelly: Running instrumented program: node ${process.argv.slice(4).join(" ")} (process ${process.pid})`); + +import {IID, Jalangi, SourceObject} from "jalangi"; +import fs from "fs"; +import path from "path"; + +declare const J$: Jalangi; + +const fileIds = new Map(); +const files: Array = []; +const fun2fun = new Map>(); +const call2fun = new Map>(); +const functionLocations = new Map(); +const callLocations = new Map(); +const funLocStack = Array(); // top-most is source location of callee function +const inAppStack = Array(); // top-most is true if in app code +let lastCallLoc: IID | null = null; // source location of most recent call site +let enterScriptLocation: SourceObject | undefined = undefined; // if not undefined, next functionEnter enters a module + +// TODO: add edges for implicit calls? calls to/from built-ins? to/from Node.js std.lib? calls to/from eval/Function? async/await? +/** + * Adds a call edge. + */ +function addCallEdge(call: IID | null, callerFun: IID, calleeFun: IID) { + let fs = fun2fun.get(callerFun); + if (!fs) { + fs = new Set; + fun2fun.set(callerFun, fs); + } + fs.add(calleeFun); + if (call) { // excluding call->function edges for implicit calls + let cs = call2fun.get(call); + if (!cs) { + cs = new Set; + call2fun.set(call, cs); + } + cs.add(calleeFun); + } +} + +/** + * Converts NodeProf SourceObject to string representation. + */ +function so2loc(s: SourceObject): string { + let fid = fileIds.get(s.name); + if (fid === undefined) { + fid = files.length; + files.push(s.name); + fileIds.set(s.name, fid); + } + return `${fid}:${s.loc.start.line}:${s.loc.start.column}:${s.loc.end.line}:${s.loc.end.column + 1}`; +} + +/** + * NodeProf instrumentation callbacks. + */ +J$.analysis = { // TODO: super calls not detected (see tests/micro/classes.js) + + /** + * Before function or constructor call. + */ + invokeFunPre: function(iid: IID, _f: Function, _base: Object, _args: any[], _isConstructor: boolean, _isMethod: boolean, _functionIid: IID, _functionSid: IID) { + lastCallLoc = iid; + }, + + /** + * Entering function. + */ + functionEnter: function(iid: IID, _func: Function, _receiver: object, _args: any[]) { + const so = J$.iidToSourceObject(iid); + const calleeEval = "eval" in so; + // determine whether the caller and/or the callee are in app code or in test packages + let callerInApp, calleeInApp; + if (inAppStack.length === 0) { // called from top-level + calleeInApp = !so.name.includes("node_modules/") && !so.name.startsWith("/") && !calleeEval; + callerInApp = false; + } else { + callerInApp = inAppStack.length > 0 && inAppStack[inAppStack.length - 1]; + if (callerInApp) {// called from app code + calleeInApp = !so.name.startsWith("/"); + if (calleeInApp) + for (const w of TEST_PACKAGES) + if (so.name.includes(`node_modules/${w}/`)) { + calleeInApp = false; + break; + } + } else // called from test package + calleeInApp = !so.name.includes("node_modules/") + } + inAppStack.push(calleeInApp); + // register call edge and call location if caller and callee are both in app code and it's an explicit call + if (callerInApp && calleeInApp && funLocStack.length > 0 && lastCallLoc && !calleeEval) { + const cso = J$.iidToSourceObject(lastCallLoc); + const callerEval = "eval" in cso; + if (!callerEval) { + addCallEdge(lastCallLoc, funLocStack[funLocStack.length - 1], iid); + if (!callLocations.has(lastCallLoc)) + callLocations.set(lastCallLoc, so2loc(cso)); + } + } + // register function location if callee is in app code + if (calleeInApp && !calleeEval && !functionLocations.has(iid)) + functionLocations.set(iid, so2loc(enterScriptLocation ?? so)); + // push function location and reset enterScriptLocation + funLocStack.push(iid); + enterScriptLocation = undefined; + lastCallLoc = null; + }, + + /** + * Exiting function. + */ + functionExit: function(_iid: IID, _returnVal, _wrappedExceptionVal) { + funLocStack.pop(); + lastCallLoc = null; + }, + + /** + * New source file loaded, apply workaround to find correct end source location. + */ + newSource: function(sourceInfo: { name: string; internal: boolean, eval?: string }, source: string) { + if ("eval" in sourceInfo) + return; // eval/Function call, not actually a new source file + // find correct end source location + let endLine = 1, last = 0; + for (let i = 0; i < source.length; i++) { + if (source[i] === '\n') { + endLine++; + last = i + 1; + } + } + const endColumn = source.length - last; + enterScriptLocation = { + name: sourceInfo.name, + loc: { + start: { line: 1, column: 1 }, + end: { line: endLine, column: endColumn } + } + }; + }, + + /** + * Before call to 'eval'. + */ + evalPre(iid: IID, str: string) { + lastCallLoc = null; + // TODO: record extra information about eval/Function calls? see --callgraph-native-calls + }, + + // evalPost(iid: IID, str: string) { + // // TODO? + // }, + + /** + * Before call to 'Function'. + */ + evalFunctionPre(iid: IID, func: Function, receiver: Object, args: any) { + lastCallLoc = null; + // TODO? + }, + + // evalFunctionPost(iid: IID, func: Function, receiver: Object, args: any, ret: any) { + // // TODO? + // }, + + /** + * Before call to built-in function. + */ + builtinEnter(name: string, f: Function, dis: any, args: any) { + lastCallLoc = null; + // TODO: record extra information about calls to built-ins? see --callgraph-native-calls and --callgraph-require-calls + }, + + // builtinExit(name: string, returnVal: any) { + // // TODO? + // }, + // + // asyncFunctionEnter(iid: IID) { + // // TODO: record extra information about async calls? see --callgraph-native-calls + // }, + // + // asyncFunctionExit(iid: IID, returnVal: any, wrappedException) { + // // TODO? + // }, + // + // awaitPre(iid: IID, valAwaited: any) { + // // TODO: record extra information about awaits? + // }, + // + // awaitPost(iid: IID, valAwaited: any, result: any, rejected: boolean) { + // // TODO? + // }, + + /** + * Before property read operation (which may trigger implicit call). + */ + getFieldPre(iid: IID, base: any, offset: any, isComputed: boolean, isOpAssign: boolean, isMethodCall: boolean): { base: any; offset: any; skip: boolean } | void { + lastCallLoc = null; + // TODO: detect implicit calls to getters? see --callgraph-implicit-calls + }, + + // getField(iid: IID, base: any, offset: any, val: any, isComputed: boolean, isOpAssign: boolean, isMethodCall: boolean): { result: any } | void { + // // TODO? + // }, + + /** + * Before property write operation (which may trigger implicit call). + */ + putFieldPre(iid: IID, base: any, offset: any, val: any, isComputed: boolean, isOpAssign: boolean): { base: any; offset: any; val: any; skip: boolean } | void { + lastCallLoc = null; + // TODO: detect implicit calls to setters? see --callgraph-implicit-calls + }, + + // putField(iid: IID, base: any, offset: any, val: any, isComputed: boolean, isOpAssign: boolean): { result: any } | void { + // // TODO? + // }, + + /** + * Before unary operator (which may trigger implicit call). + */ + unaryPre(iid: IID, op: string, left: any): { op: string; left: any; skip: boolean } | void { + lastCallLoc = null; + // TODO: detect implicit calls to valueOf? see --callgraph-implicit-calls + }, + + // unary(iid: IID, op: string, left: any, result: any): { result: any } | void { + // // TODO? + // }, + + /** + * Before binary operator (which may trigger implicit call). + */ + binaryPre(iid: IID, op: string, left: any, right: any, isOpAssign: boolean, isSwitchCaseComparison: boolean, isComputed: boolean): { op: string; left: any; right: any; skip: boolean } | void { + lastCallLoc = null; + // TODO: detect implicit calls to valueOf/toString? see --callgraph-implicit-calls + }, + + // binary(iid: IID, op: string, left: any, right: any, result: any, isOpAssign: boolean, isSwitchCaseComparison: boolean, isComputed: boolean): { result: any } | void { + // // TODO? + // } +}; + +/** + * Program exit, write call graph to JSON file. + * (Note, funLocStack is nonempty if exit happens because of process.exit.) + */ +process.on('exit', function() { + if (files.length === 0) { + console.log(`jelly: No relevant files detected for process ${process.pid}, skipping file write`); + return; + } + // console.log(`jelly: Writing ${outfile}`); + const fd = fs.openSync(outfile, "w"); + fs.writeSync(fd, `{\n "entries": [${JSON.stringify(path.relative(process.cwd(), process.argv[1]))}],\n`); + fs.writeSync(fd, ` "time": "${new Date().toUTCString()}",\n`); + fs.writeSync(fd, ` "files": [`); + let first = true; + for (const file of files) { + fs.writeSync(fd, `${first ? "" : ","}\n ${JSON.stringify(file)}`); + first = false; + } + fs.writeSync(fd, `\n ],\n "functions": {`); + first = true; + for (const [iid, loc] of functionLocations) { + fs.writeSync(fd, `${first ? "" : ","}\n "${iid}": ${JSON.stringify(loc)}`); + first = false; + } + fs.writeSync(fd, `\n },\n "calls": {`); + first = true; + for (const [iid, loc] of callLocations) { + fs.writeSync(fd, `${first ? "" : ","}\n "${iid}": ${JSON.stringify(loc)}`); + first = false; + } + fs.writeSync(fd, `\n },\n "fun2fun": [`); + first = true; + for (const [callerFun, callees] of fun2fun) + for (const callee of callees) { + fs.writeSync(fd, `${first ? "\n " : ", "}[${callerFun}, ${callee}]`); + first = false; + } + fs.writeSync(fd, `${first ? "" : "\n "}],\n "call2fun": [`); + first = true; + for (const [call, callees] of call2fun) + for (const callee of callees) { + fs.writeSync(fd, `${first ? "\n " : ", "}[${call}, ${callee}]`); + first = false; + } + fs.writeSync(fd, `${first ? "" : "\n "}]\n}\n`); + fs.closeSync(fd); +}); diff --git a/src/dynamic/soundnesstester.ts b/src/dynamic/soundnesstester.ts new file mode 100644 index 0000000..65e9201 --- /dev/null +++ b/src/dynamic/soundnesstester.ts @@ -0,0 +1,162 @@ +import {readFileSync} from "fs"; +import {DummyModuleInfo, FunctionInfo, ModuleInfo} from "../analysis/infos"; +import logger from "../misc/logger"; +import {arrayToString, percent, sourceLocationToStringWithFile, sourceLocationToStringWithFileAndEnd} from "../misc/util"; +import {CallGraph} from "callgraph"; +import {AnalysisState} from "../analysis/analysisstate"; +import path from "path"; +import {options} from "../options"; + +/** + * Performs soundness testing of the analysis result using the given dynamic call graph. + * @return [number of dynamic function->function call edges matched, + * total number of dynamic function->function call edges, + * number of dynamic call->function call edges matched, + * total number of dynamic call->function call edges] + */ +export function testSoundness(jsonfile: string, analysisState: AnalysisState): [number, number, number, number] { + + // collect all static functions including module top-level functions (excluding aliases) + const staticFunctions = new Map(); + for (const m of analysisState.moduleInfos.values()) + if (m.loc) // TODO: m.loc may be empty with --ignore-dependencies + staticFunctions.set(`${m.path}:${m.loc.start.line}:${m.loc.start.column + 1}:${m.loc.end.line}:${m.loc.end.column + 1}`, m); + for (const f of analysisState.functionInfos.values()) + if (!f.loc || "nodeIndex" in f.loc) + analysisState.warn(`Source location missing for function ${f.name || ""} in ${f.moduleInfo.path}`); + else + staticFunctions.set(`${f.moduleInfo.path}:${f.loc.start.line}:${f.loc.start.column + 1}:${f.loc.end.line}:${f.loc.end.column + 1}`, f); + + // log static locations + if (logger.isDebugEnabled()) { + logger.debug(`Static files: ${arrayToString(Array.from(analysisState.moduleInfos.keys()), "\n ")}`); + logger.debug(`Static functions: ${arrayToString(Array.from(staticFunctions.keys()), "\n ")}`); + logger.debug(`Static calls: ${arrayToString(Array.from(analysisState.callLocations), "\n ")}`); + logger.debug(`Ignored functions: ${arrayToString(analysisState.artificialFunctions.map(([, n]) => sourceLocationToStringWithFile(n.loc)), "\n ")}`); + // TODO: optionally ignore files that haven't been analyzed? (relevant with --ignore-dependencies) + } + + // load the dynamic call graph + const dyn = JSON.parse(readFileSync(jsonfile, "utf8")) as CallGraph; + + // collect dynamic files and check that they have been analyzed + const dynamicFiles = new Map(); + for (const file of dyn.files) { + const f = path.resolve(options.basedir, file); + dynamicFiles.set(dynamicFiles.size, f); + if (!analysisState.moduleInfos.has(f)) + logger.warn(`File ${file} not found in static call graph`); + // else + // logger.debug(`Found file ${file}`); + } + + // finds the representative for the given source location + function findRepresentativeLocation(loc: string): string { + const c = loc.indexOf(":"); + const file = dynamicFiles.get(Number(loc.substring(0, c)))!; + const rest = loc.substring(c + 1); + const m = analysisState.moduleInfos.get(file); + return `${m ? m.path : file}:${rest}`; + } + + // collect dynamic functions and check that they have been analyzed + const dynamicFunctionLocs = new Map(); + const dynamicFunctions = new Map(); + const ignoredFunctions = new Set(); + for (const [,n] of analysisState.artificialFunctions) + ignoredFunctions.add(sourceLocationToStringWithFile(n.loc) + ":"); + const comp = ([, loc1]: [string, string], [, loc2]: [string, string]) => loc1 < loc2 ? -1 : loc1 > loc2 ? 1 : 0; + for (const [f, loc] of Object.entries(dyn.functions).sort(comp)) { + const reploc = findRepresentativeLocation(loc); + dynamicFunctionLocs.set(Number(f), reploc); + const fun = staticFunctions.get(reploc); + if (!fun) { + if (!ignoredFunctions.has(reploc.substring(0, reploc.lastIndexOf(":", reploc.lastIndexOf(":") - 1) + 1))) // dyn.ts sometimes reports incorrect end locations, so we only consider start locations + logger.warn(`Function ${reploc} not found in static call graph`); + else + logger.debug(`Function ${reploc} from dynamic call graph ignored`); // filtering away artificial call edges reported by dyn.ts + } else { + dynamicFunctions.set(Number(f), fun); + // logger.debug(`Found function ${loc}`); + } + } + + // collect dynamic calls and check whether they have been analyzed + const callStrLocations = new Set(); + for (const n of analysisState.callLocations) + callStrLocations.add(sourceLocationToStringWithFileAndEnd(n.loc)); + const dynamicCallLocs = new Map(); + for (const [f, loc] of Object.entries(dyn.calls).sort(comp)) { + const reploc = findRepresentativeLocation(loc); + dynamicCallLocs.set(Number(f), reploc); + if (!callStrLocations.has(reploc)) + logger.warn(`Call ${reploc} not found in static call graph`); + } + + const warnings: Array = []; + + // check fun2fun edges + let found1 = 0, missed1 = 0; + for (const [from, to] of dyn.fun2fun) { + const callerFun = dynamicFunctions.get(from); + const calleeFun = dynamicFunctions.get(to); + let found = false; + if (callerFun && calleeFun) { + if (calleeFun instanceof FunctionInfo) { + const fs = analysisState.functionToFunction.get(callerFun); + if (fs && fs.has(calleeFun)) + found = true; + } else { + const ms = analysisState.requireGraph.get(callerFun); + if (ms && ms.has(calleeFun)) + found = true; + } + } + if (found) + found1++; + else { + warnings.push(`Call edge missing in static call graph: function ${dynamicFunctionLocs.get(from)} -> function ${dynamicFunctionLocs.get(to)}`); + missed1++; + } + } + const total1 = found1 + missed1; + + // check call2fun edges + const callStrToFunction = new Map>(); + for (const [n, s] of analysisState.callToFunction) + callStrToFunction.set(sourceLocationToStringWithFileAndEnd(n.loc), s); + const callStrToModule = new Map>(); + for (const [n, s] of analysisState.callToModule) + callStrToModule.set(sourceLocationToStringWithFileAndEnd(n.loc), s) + let found2 = 0, missed2 = 0; + for (const [from, to] of dyn.call2fun) { + const callLoc = dynamicCallLocs.get(from); + const calleeFun = dynamicFunctions.get(to); + let found = false; + if (callLoc && calleeFun) { + if (calleeFun instanceof FunctionInfo) { + const fs = callStrToFunction.get(callLoc); + if (fs && fs.has(calleeFun)) + found = true; + } else { + const ms = callStrToModule.get(callLoc); + if (ms && ms.has(calleeFun)) + found = true; + } + } + if (found) + found2++; + else { + warnings.push(`Call edge missing in static call graph: call ${dynamicCallLocs.get(from)} -> function ${dynamicFunctionLocs.get(to)}`); + missed2++; + } + } + const total2 = found2 + missed2; + + // report and return results + for (const m of warnings.sort()) + logger.warn(m); + logger.info(`Dynamic function->function call edges matched: ${found1}/${total1}${total1 > 0 ? ` (recall: ${percent(found1 / total1)})` : ""}`); + logger.info(`Dynamic call->function call edges matched: ${found2}/${total2}${total2 > 0 ? ` (recall: ${percent(found2 / total2)})` : ""}`); + return [found1, total1, found2, total2]; +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..156c201 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,353 @@ +#!/usr/bin/env node + +import {analyzeFiles} from "./analysis/analyzer"; +import {closeSync, openSync, readdirSync, readFileSync, unlinkSync} from "fs"; +import {program} from "commander"; +import logger, {logToFile, setLogLevel} from "./misc/logger"; +import {testSoundness} from "./dynamic/soundnesstester"; +import {options, setDefaultTrackedModules, setOptions, setPatternProperties} from "./options"; +import {spawnSync} from "child_process"; +import path from "path"; +import {autoDetectBaseDir, expand, writeStreamedStringify} from "./misc/files"; +import {tapirPatternMatch} from "./patternmatching/tapirpatterns"; +import {toDot} from "./output/graphviz"; +import {AnalysisStateReporter} from "./output/analysisstatereporter"; +import {TypeScriptTypeInferrer} from "./typescript/typeinferrer"; +import {getAPIUsage, reportAPIUsage} from "./patternmatching/apiusage"; +import { + convertTapirPatterns, + getGlobs, + getProperties, + loadTapirDetectionPatternFiles, + removeObsoletePatterns +} from "./patternmatching/patternloader"; +import {compareCallGraphs} from "./output/compare"; +import {getMemoryLimit} from "./misc/memory"; +import Solver from "./analysis/solver"; +import {exportCallGraphHtml, exportDataFlowGraphHtml} from "./output/visualizer"; +import {VulnerabilityDetector, VulnerabilityResults} from "./patternmatching/vulnerabilitydetector"; +import {Vulnerability} from "vulnerabilities"; +import {addAll} from "./misc/util"; +import {getAPIExported, reportAccessPaths, reportAPIExportedFunctions} from "./patternmatching/apiexported"; +import {merge} from "./output/merge"; +import {CallGraph} from "callgraph"; + +const VERSION = require("../package.json").version; +const PKG = "pkg" in process; + +program + .name("jelly") + .version(VERSION) + .addHelpText("before", "Copyright (C) 2023 Anders Møller\n") + .option("-b, --basedir ", "base directory for files to analyze (default: auto-detect)") + .option("-f, --logfile ", "log to file (default: log to stdout)") + .option("-l, --loglevel ", "log level (debug/verbose/info/warn/error)", "info") + .option("-i, --timeout ", "limit analysis time") + .option("-a, --dataflow-html ", "save data-flow graph as HTML file") + .option("-m, --callgraph-html ", "save call graph as HTML file") + .option("-j, --callgraph-json ", "save call graph as JSON file") + .option("-s, --soundness ", "compare with dynamic call graph") + .option("-n, --graal-home ", "home of graal-nodejs (default: $GRAAL_HOME)") + .option("-d, --dynamic ", "generate call graph dynamically, no static analysis") + .option("-e, --exclude ", "files to exclude when specifying entry directories") + .option("-p, --patterns ", "files containing API usage patterns to detect") + .option("-v, --vulnerabilities ", "report vulnerability matches") + // .option("-g, --callgraph-graphviz ", "save call graph as Graphviz dot file") // TODO: graphviz output disabled for now + .option("--npm-test ", "run 'npm test' instead of 'node' (use with -d)") + // .option("--graphviz-packages ", "packages to include in Graphviz dot file (use with -g)") + // .option("--graphviz-elide-functions", "elide functions (use with -g)") + // .option("--graphviz-dependencies-only", "show module dependencies only (use with -g)") + .option("--tokens-json ", "save tokens for constraint variables as JSON file") + .option("--tokens", "report tokens for constraint variables") + .option("--largest", "report largest token sets and subset relations") + // .option("--bottom-up", "analyze bottom-up in package dependency structure") // TODO: bottom-up analysis disabled for now + .option("--no-alloc", "disable light-weight allocation site abstraction") + .option("--no-widening", "disable widening") + .option("--no-patch-dynamics", "disable patching of dynamic property accesses") + .option("--no-cycle-elimination", "disable cycle elimination") + .option("--no-natives", "disable nonessential models of native libraries") + .option("--skip-graal-test", "skip graal-nodejs test (use with -d)") + .option("--ignore-dependencies", "don't include dependencies in analysis") + .option("--ignore-unresolved", "don't report errors about unresolved modules") + .option("--no-print-progress", "don't print analysis progress information") + .option("--no-tty", "don't print solver progress for TTY") + .option("--warnings-unsupported", "print warnings about unsupported features") + .option("--gc", "enable garbage collection for more accurate memory usage reporting") + .option("--typescript", "enable TypeScript type inference (use with -p)") + .option("--api-usage", "report API usage of external packages (implies --ignore-dependencies)") + .option("--api-exported", "report API of modules") + .option("--find-access-paths ", "find access paths for source location (file:line)") + .option("--higher-order-functions", "report higher-order functions") + .option("--zeros", "report calls with zero callees and functions with zero callers") + .option("--tracked-modules ", "modules to track usage of (default: empty unless using -p, -v or --api-usage)") + .option("--no-callgraph-implicit", "omit implicit calls in call graph") // TODO: not yet including implicit valueOf/toString calls + .option("--no-callgraph-native", "omit native calls in call graph") // TODO: not yet including the native functions themselves, only callbacks from native functions + .option("--no-callgraph-require", "omit module loading in call graph") // TODO: currently works only for modules that are resolved successfully (and included even if --ignore-dependencies is used)? + .option("--no-callgraph-external", "omit heuristic external callbacks in call graph") + .option("--diagnostics", "report internal analysis diagnostics") + .option("--diagnostics-json ", "save analysis diagnostics in JSON file") + .option("--variable-kinds", "report constraint variable kinds") + .option("--max-rounds ", "limit number of fixpoint rounds for each module and package") + .option("--typescript-library-usage ", "save TypeScript library usage in JSON file, no analysis") + .option("--modules-only", "report reachable packages and modules only, no analysis") + .option("--compare-callgraphs", "compare two call graphs given as JSON files, no analysis") + .usage("[options] [files]") + .addHelpText("after", + "\nAll modules reachable by require/import from the given files are included in the analysis\n" + + "(except when using --ignore-dependencies). If specifying directories instead\n" + + "of files, the files in the directories and their subdirectories are used as entry points.\n" + + "The special argument -- can be used indicate end of options, typically after multi-argument options.\n" + + `Memory limit is ${getMemoryLimit()}MB.${PKG ? "" : " Change with, for example: NODE_OPTIONS=--max-old-space-size=4096"}`) + .action(main) + .showHelpAfterError() + .parse(); + +async function main() { + options.tty = true; + setOptions(program.opts()); + if (options.logfile) + logToFile(options.logfile); + setLogLevel(options.loglevel); + + if (PKG) + for (const opt of ["dynamic"] as const) + if (options[opt]) { + logger.error(`Error: Option --${opt} not available in binary executable`); + process.exitCode = -1; + return; + } + + if (options.compareCallgraphs) { + if (program.args.length !== 2) { + logger.error(`Error: Option --compare-callgraphs expects two files`); + process.exitCode = -1; + return; + } + compareCallGraphs(program.args[0], program.args[1]); + return; + } + + if (options.patterns && options.vulnerabilities) { // TODO: also check this in server.ts + logger.error(`Error: Options --patterns and --vulnerabilities cannot be used together`); // pattern match confidence computation requires relevant libraries to be external + process.exitCode = -1; + return; + } + + if (options.gc && typeof gc !== "function") { + // restart with node option --expose-gc if --gc is enabled + const args = process.argv.slice(1); + args.unshift("--expose-gc"); + const t = spawnSync(process.execPath, args, {stdio: "inherit"}); + if (t.status === null) { + logger.error("Error: Unable to restart with --expose-gc"); + process.exitCode = -1; + } else + process.exitCode = t.status; + return; + } + + if (options.dynamic) { + + const graalHome = options.graalHome || process.env.GRAAL_HOME; + const node = graalHome ? path.resolve(graalHome, "bin/node") : "node"; + if (!options.skipGraalTest) { + logger.info("Testing graal-nodejs") + const t = spawnSync(node, ["-e", "process.exit(typeof Graal === 'object' ? 0 : -1)"]); + if (t.status === null) { + logger.error(`Error: Unable to execute ${node}`); + process.exitCode = -1; + return; + } + if (t.status !== 0) { + logger.error("Error: 'node' is not graal-nodejs, try option --graal-home or environment variable GRAAL_HOME"); + process.exitCode = -1; + return; + } + } + logger.info("Generating dynamic call graph"); + let cmd, args, cwd; + if (options.npmTest) { + cmd = "npm"; + args = ["test", ...program.args]; + cwd = path.resolve(options.npmTest) + } else { + if (program.args.length === 0) { + logger.info("File missing, aborting"); + return; + } + cmd = `${__dirname}/bin/node`; + args = program.args; + cwd = process.cwd() + } + const dyn = path.resolve(options.dynamic); + const t = spawnSync(cmd, args, { + stdio: "inherit", + cwd, + env: { + ...process.env, + JELLY_OUT: dyn, + GRAAL_HOME: graalHome ? path.resolve(graalHome) : undefined, + PATH: `${__dirname}/bin${path.delimiter}${process.env.PATH}` + } + }); + if (t.status === null) { + logger.error(`Error: Unable to execute ${cmd}`); + process.exitCode = -1; + return; + } + + const dir = path.dirname(dyn); + const cgs: Array = []; + for (const f of readdirSync(dir, {withFileTypes: true})) + if (f.isFile()) { + const p = path.resolve(dir, f.name); + if (p.startsWith(`${dyn}-`)) { // instrumented execution has produced $JELLY-OUT- files + cgs.push(JSON.parse(readFileSync(p, 'utf-8')) as CallGraph); + unlinkSync(p); + } + } + const fd = openSync(dyn, "w"); + writeStreamedStringify(merge(cgs), fd); // TODO: alert if the call graph is empty? + closeSync(fd); + logger.info(`Dynamic call graph written to ${dyn}`); + + } else { + + if (program.args.length === 0) { + logger.info("No files to analyze (use --help to see usage)"); + return; + } + + if (!autoDetectBaseDir(program.args)) + return; + const files = expand(program.args); + if (logger.isVerboseEnabled()) { + logger.verbose("Entry files:"); + for (const file of files) + logger.verbose(` ${file}`); + } + + if (options.typescriptLibraryUsage) { + + const ts = new TypeScriptTypeInferrer(files); + const fd = openSync(options.typescriptLibraryUsage, "w"); + writeStreamedStringify(ts.libraryUsageToJSON(ts.getLibraryUsage()), fd); + closeSync(fd); + logger.info(`TypeScript library usage written to ${options.typescriptLibraryUsage}`); + + } else { + + let tapirPatterns, patterns, globs, props, vulnerabilityDetector; + if (options.patterns) { + tapirPatterns = removeObsoletePatterns(loadTapirDetectionPatternFiles(options.patterns)); + patterns = convertTapirPatterns(tapirPatterns); + globs = getGlobs(patterns); + props = getProperties(patterns); + } + if (options.vulnerabilities) { + logger.info(`Loading vulnerability patterns from ${options.vulnerabilities}`); + vulnerabilityDetector = new VulnerabilityDetector(JSON.parse(readFileSync(options.vulnerabilities, "utf8")) as Array); // TODO: use when setting globs and props? (see also server.ts) + const ps = vulnerabilityDetector.getPatterns(); + addAll(getGlobs(ps), (globs = (globs ?? new Set()))); + addAll(getProperties(ps), (props = (props ?? new Set()))); + } + + setDefaultTrackedModules(globs); + setPatternProperties(options.apiUsage ? undefined : (props || new Set())); + + const solver = new Solver(); + const a = solver.analysisState; + a.vulnerabilities = vulnerabilityDetector; + await analyzeFiles(files, solver); + const f = solver.fragmentState; + const out = new AnalysisStateReporter(a, f); + + let typer: TypeScriptTypeInferrer | undefined; + if (options.typescript) + typer = new TypeScriptTypeInferrer(files); + + let vr: VulnerabilityResults = {}; + if (vulnerabilityDetector) { + vr.package = vulnerabilityDetector.findPackagesThatMayDependOnVulnerablePackages(a); + vr.module = vulnerabilityDetector.findModulesThatMayDependOnVulnerableModules(a); + vr.function = vulnerabilityDetector.findFunctionsThatMayReachVulnerableFunctions(a); + vr.call = vulnerabilityDetector.findCallsThatMayReachVulnerableFunctions(a, vr.function); + vulnerabilityDetector.reportResults(a, vr); + vr.matches = vulnerabilityDetector.patternMatch(a, f, typer, solver.diagnostics); + // TODO: find functions that may reach functions in vulnerabilities.matches + } + + if (options.callgraphHtml) { + const file = options.callgraphHtml; + exportCallGraphHtml(a, file, vr); + logger.info(`Call graph written to ${file}`); + } + + if (options.dataflowHtml) { + const file = options.dataflowHtml; + exportDataFlowGraphHtml(a, f, file); // TODO: also show pattern matches and reachability + logger.info(`Data-flow graph written to ${file}`); + } + + if (options.callgraphGraphviz) { + const file = options.callgraphGraphviz; + const fd = openSync(file, "w"); + toDot(a, fd); + closeSync(fd); + logger.info(`Call graph written to ${file}`); + } + + if (options.tokens) + out.reportTokens(); + + if (options.tokensJson) + out.saveTokens(options.tokensJson); + + if (options.largest) { + out.reportLargestSubsetEdges(); + out.reportLargestTokenSets(); + } + + if (options.callgraphJson) + out.saveCallGraph(options.callgraphJson, files); + + if (options.diagnosticsJson) + out.saveDiagnostics(solver.diagnostics, options.diagnosticsJson); + + if (options.modulesOnly) + out.reportReachablePackagesAndModules(); + + if (options.soundness) + testSoundness(options.soundness, a); + + if (tapirPatterns && patterns) + tapirPatternMatch(tapirPatterns, patterns, a, f, typer, undefined, solver.diagnostics); + + if (options.apiUsage) { + const [r1, r2] = getAPIUsage(a); + reportAPIUsage(r1, r2); + } + + if (options.apiExported || options.findAccessPaths) { + const r = getAPIExported(a, f); + if (options.apiExported) + reportAPIExportedFunctions(r); + if (options.findAccessPaths) + reportAccessPaths(a, r, options.findAccessPaths); + } + + if (options.higherOrderFunctions) + out.reportHigherOrderFunctions(); + + if (options.zeros) { + const funs = out.getZeroCallerFunctions(); + out.reportZeroCallerFunctions(funs); + const calls = out.getZeroCalleeCalls(); + out.reportZeroCalleeCalls(calls); + } + + if (options.variableKinds) + out.reportVariableKinds(); + } + } +} \ No newline at end of file diff --git a/src/misc/asthelpers.ts b/src/misc/asthelpers.ts new file mode 100644 index 0000000..aed26cf --- /dev/null +++ b/src/misc/asthelpers.ts @@ -0,0 +1,131 @@ +import { + CallExpression, + Class, + ClassAccessorProperty, + ClassMethod, + ClassPrivateMethod, + ClassPrivateProperty, + ClassProperty, + Expression, + Identifier, + ImportDefaultSpecifier, + ImportSpecifier, + isCallExpression, + isClassPrivateProperty, + isExpression, + isExpressionStatement, + isIdentifier, + isImportSpecifier, + isJSXMemberExpression, + isMemberExpression, + isNumericLiteral, + isOptionalMemberExpression, + isParenthesizedExpression, + isStringLiteral, + JSXMemberExpression, + MemberExpression, + NewExpression, + ObjectMethod, + ObjectProperty, + OptionalCallExpression, + OptionalMemberExpression, + StringLiteral +} from "@babel/types"; +import {NodePath} from "@babel/traverse"; +import {CallNodePath} from "../natives/nativebuilder"; + +/** + * Finds the property name of a property access, returns undefined if dynamic and not literal string or number. + * (See also getKey below.) + */ +export function getProperty(node: MemberExpression | OptionalMemberExpression | JSXMemberExpression): string | undefined { + if (isJSXMemberExpression(node)) + return node.property.name; + else if (isIdentifier(node.property) && !node.computed) + return node.property.name; + else if (isStringLiteral(node.property)) + return node.property.value; + else if (isNumericLiteral(node.property)) + return node.property.value.toString(); + return undefined; +} + +/** + * Finds the property name of an object/class property/method definition, returns undefined if dynamic and not literal string or number. + * (See also getProperty above.) + */ +export function getKey(node: ObjectProperty | ClassProperty | ClassAccessorProperty | ClassPrivateProperty | ObjectMethod | ClassMethod | ClassPrivateMethod): string | undefined { + if (isClassPrivateProperty(node)) + return node.key.id.name; + if (isIdentifier(node.key) && !node.computed) + return node.key.name; + else if (isStringLiteral(node.key)) + return node.key.value; + else if (isNumericLiteral(node.key)) + return node.key.value.toString(); + return undefined; +} + +/** + * Checks whether the parent node (possibly in parentheses) is an expression statement. + */ +export function isParentExpressionStatement(path: NodePath): boolean { // TODO: also include nodes that are non-last in expression sequences? + let p: NodePath | null = path; + do { + p = p.parentPath; + } while (p && isParenthesizedExpression(p)); + return p !== null && isExpressionStatement(p.node); +} + +/** + * Returns the base expression and property of the given method call, or undefined if not applicable. + */ +export function getBaseAndProperty(path: CallNodePath): {base: Expression, property: MemberExpression["property"]} | undefined { + let p: NodePath | null = path.get("callee") as NodePath; + while (isParenthesizedExpression(p.node)) + p = p.get("expression") as NodePath; + if (!(isMemberExpression(p.node) || isOptionalMemberExpression(p.node))) + return undefined; + let base = p.node.object; + if (!isExpression(base)) // excluding Super + return undefined; + let property = p.node.property; + return {base, property}; +} + +/** + * Finds the exported property name for an export specifier. + */ +export function getExportName(exported: Identifier | StringLiteral): string { + return isIdentifier(exported) ? exported.name : exported.value; +} + +/** + * Finds the imported property name for an import specifier. + */ +export function getImportName(imp: ImportSpecifier | ImportDefaultSpecifier): string { + return isImportSpecifier(imp) ? isIdentifier(imp.imported) ? imp.imported.name : imp.imported.value : "default"; +} + +/** + * Finds the enclosing ClassDeclaration or ClassExpression of the given node path. + */ +export function getClass(path: NodePath): Class | undefined { + return (path.find((p) => p.isClass()) as NodePath)?.node; +} + +/** + * Returns true if the given node may be used as a Promise. + * If the node is a callee in a call node or the receiver in a property read that is not 'then' or 'catch', + * then false is returned, and otherwise true. + * From tapir.ts. + */ +export function isMaybeUsedAsPromise(path: NodePath): boolean { + return !isExpressionStatement(path.node) && + // The call is definitely not used as a Promise if the node is a callee in a call node + !(isCallExpression(path.parent) && path.parent.callee === path.node) && + // The call is definitely not used as a Promise if the receiver in a property read that is not then or catch + !(isMemberExpression(path.parent) && + isIdentifier(path.parent.property) && + !['then', 'catch'].includes(path.parent.property.name)); +} diff --git a/src/misc/files.ts b/src/misc/files.ts new file mode 100644 index 0000000..7dcc56d --- /dev/null +++ b/src/misc/files.ts @@ -0,0 +1,218 @@ +import {closeSync, existsSync, lstatSync, openSync, readdirSync, readFileSync, readSync, writeSync} from "fs"; +import {basename, relative, resolve, sep} from "path"; +import {options} from "../options"; +import micromatch from "micromatch"; +import {FilePath, sourceLocationToStringWithFile} from "./util"; +import logger from "./logger"; +import {SourceLocation} from "@babel/types"; +import {findPackageJson} from "./packagejson"; +import {AnalysisState} from "../analysis/analysisstate"; +import {tsResolveModuleName} from "../typescript/moduleresolver"; +import stringify from "stringify2stream"; + +/** + * Expands the given list of file paths. + * Each given file path is resolved relative to the current working directory. + * Directories are traversed recursively (except node_modules, .git, and .yarn, + * and also excluding out, build, dist, generated and sub-directories that contain package.json unless inside a node_modules directory within basedir), + * and all .js, .es, .mjs, .cjs, .ts, .tsx and Node.js shebang files are included + * (except .d.ts and paths matching options.exclude and also excluding .min.js, .bundle.js unless inside a node_modules directory within basedir). + * Symlinks are ignored. + * The resulting paths are relative to options.basedir. + */ +export function expand(paths: Array | string): Array { + if (typeof paths === "string") + paths = [paths]; + const res: Array = []; + for (const path of paths) + for (const e of expandRec(resolve(path), false)) + res.push(e); // TODO: complain if e starts with "."? (happens if path is outside basedir) + if (options.exclude) { + const excl = new Set(micromatch(res, options.exclude)); + const eres = []; + for (const r of res) + if (!excl.has(r)) + eres.push(r); + return eres; + } else + return res; +} + +function* expandRec(path: string, sub: boolean): Generator