From 54f305e85575865cb71eacea372e974e236df667 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Fri, 1 Dec 2023 04:35:16 +0100 Subject: [PATCH 01/34] feat: monorepo/playground rewrite --- .eslintrc | 41 - .eslintrc.cjs | 6 + .github/workflows/ci.yml | 33 + .github/workflows/publish.yml | 26 +- .github/workflows/test.yml | 36 - .gitignore | 14 +- .npmrc | 1 + .prettierrc | 1 + .vscode/launch.json | 8 +- .vscode/settings.json | 7 + CONTRIBUTING.md | 40 +- LICENSE | 21 - apps/docs/package.json | 17 + apps/docs/src/.vitepress/config.ts | 60 + apps/docs/src/.vitepress/theme/custom.css | 14 + apps/docs/src/.vitepress/theme/index.ts | 6 + apps/docs/src/assets/webpack-structure.png | Bin 0 -> 184707 bytes apps/docs/src/concepts/deobfuscate.md | 28 + apps/docs/src/concepts/jsx.md | 25 + apps/docs/src/concepts/unminify.md | 20 + apps/docs/src/concepts/unpack.md | 132 + apps/docs/src/guide/api.md | 92 + apps/docs/src/guide/cli.md | 61 + apps/docs/src/guide/introduction.md | 33 + apps/docs/src/guide/web.md | 34 + apps/docs/src/index.md | 27 + apps/docs/tsconfig.json | 6 + apps/playground/.eslintrc.cjs | 5 + apps/playground/README.md | 1 + apps/playground/index.html | 16 + apps/playground/package.json | 36 + apps/playground/postcss.config.js | 6 + apps/playground/public/vite.svg | 1 + apps/playground/src/App.tsx | 183 + apps/playground/src/_empty.ts | 1 + apps/playground/src/assets/solid.svg | 1 + .../playground/src/components/Breadcrumbs.tsx | 18 + .../src/components/DirectoryNode.tsx | 49 + apps/playground/src/components/FileNode.tsx | 26 + apps/playground/src/components/FileTree.tsx | 107 + .../src/components/MonacoEditor.tsx | 124 + apps/playground/src/components/Sidebar.tsx | 233 + apps/playground/src/components/Tab.tsx | 31 + .../src/context/DeobfuscateContext.tsx | 87 + apps/playground/src/hooks/useTheme.ts | 31 + apps/playground/src/index.css | 7 + apps/playground/src/index.tsx | 9 + apps/playground/src/monaco/eval-selection.ts | 120 + .../src/monaco/placeholder-widget.ts | 49 + apps/playground/src/sandbox.ts | 12 + apps/playground/src/vite-env.d.ts | 1 + apps/playground/src/webcrack.worker.ts | 57 + apps/playground/tailwind.config.ts | 36 + apps/playground/tsconfig.json | 12 + apps/playground/turbo.json | 11 + apps/playground/vite.config.ts | 49 + apps/web/netlify.toml | 3 + apps/web/package.json | 13 + package-lock.json | 7380 ----------------- package.json | 82 +- packages/ast-utils/.eslintrc.cjs | 5 + packages/ast-utils/package.json | 29 + packages/ast-utils/src/ast.ts | 13 + packages/ast-utils/src/generator.ts | 23 + packages/ast-utils/src/index.ts | 6 + .../ast-utils/src}/inline.ts | 50 +- .../ast-utils/src}/matcher.ts | 60 +- {src => packages/ast-utils/src}/matchers.d.ts | 14 +- .../ast-utils/src}/rename.ts | 31 +- .../ast-utils/src/transform.ts | 40 +- packages/ast-utils/test/rename.test.ts | 81 + packages/ast-utils/test/setup.ts | 8 + packages/ast-utils/tsconfig.json | 3 + packages/ast-utils/vitest.config.ts | 11 + packages/config-eslint/index.js | 18 + packages/config-eslint/package.json | 11 + packages/config-typescript/base.json | 24 + packages/config-typescript/package.json | 5 + packages/config-typescript/vite.json | 22 + packages/deobfuscate/.eslintrc.cjs | 5 + packages/deobfuscate/package.json | 30 + .../deobfuscate/src/array-rotator.ts | 38 +- .../deobfuscate/src/control-flow-object.ts | 75 +- .../deobfuscate/src/control-flow-switch.ts | 54 +- .../deobfuscate/src/dead-code.ts | 29 +- .../deobfuscate/src/debug-protection.ts | 50 +- .../deobfuscate/src}/decoder.ts | 37 +- packages/deobfuscate/src/index.ts | 69 + .../deobfuscate/src/inline-decoded-strings.ts | 19 +- .../deobfuscate/src/inline-decoder-wappers.ts | 16 +- .../deobfuscate/src/inline-object-props.ts | 38 +- packages/deobfuscate/src/matchers.d.ts | 41 + .../src/merge-object-assignments.ts | 32 +- .../deobfuscate/src/self-defending.ts | 62 +- .../deobfuscate/src/string-array.ts | 32 +- .../deobfuscate/src}/vm.ts | 40 +- .../__snapshots__/deobfuscate.test.ts.snap | 0 .../__snapshots__/deobfuscator.test.ts.snap | 159 + packages/deobfuscate/test/deobfuscate.test.ts | 90 + packages/deobfuscate/test/index.ts | 14 + .../test/inline-object-props.test.ts | 119 + .../test/merge-object-assignments.test.ts | 63 + .../samples/obfuscator.io-calls-transform.js | 0 .../obfuscator.io-control-flow-keys.js | 0 ...obfuscator.io-control-flow-partial-keys.js | 0 ...bfuscator.io-control-flow-split-strings.js | 0 .../obfuscator.io-control-flow-spread.js | 0 ...bfuscator.io-control-flow-switch-return.js | 0 .../samples/obfuscator.io-control-flow.js | 0 .../samples/obfuscator.io-function-wrapper.js | 0 .../test}/samples/obfuscator.io-high.js | 0 .../samples/obfuscator.io-multi-encoders.js | 0 .../samples/obfuscator.io-rotator-unary.js | 0 .../test}/samples/obfuscator.io.js | 0 .../test}/samples/simple-string-array.js | 0 packages/deobfuscate/test/setup.ts | 8 + packages/deobfuscate/tsconfig.json | 3 + packages/deobfuscate/vitest.config.ts | 11 + packages/unminify/.eslintrc.cjs | 5 + packages/unminify/package.json | 33 + packages/unminify/src/index.ts | 29 + packages/unminify/src/matchers.d.ts | 41 + .../src/transforms/block-statements.ts | 9 +- .../src/transforms/computed-properties.ts | 23 +- packages/unminify/src/transforms/index.ts | 14 + .../unminify/src/transforms/json-parse.ts | 17 +- .../unminify/src/transforms/logical-to-if.ts | 21 +- .../unminify/src/transforms/merge-else-if.ts | 26 + .../unminify/src/transforms/merge-strings.ts | 22 +- .../src/transforms/number-expressions.ts | 35 +- .../unminify/src/transforms/raw-literals.ts | 7 +- .../unminify/src}/transforms/sequence.ts | 57 +- .../transforms/split-variable-declarations.ts | 25 +- .../unminify/src/transforms/ternary-to-if.ts | 15 +- .../src/transforms/unminify-booleans.ts | 30 + .../src/transforms/void-to-undefined.ts | 25 + .../unminify/src}/transforms/yoda.ts | 45 +- .../unminify/test/block-statements.test.ts | 66 + .../unminify/test/computed-properties.test.ts | 41 + packages/unminify/test/index.ts | 14 + packages/unminify/test/json-parse.test.ts | 24 + packages/unminify/test/logical-to-if.test.ts | 23 + packages/unminify/test/merge-else-if.test.ts | 25 + packages/unminify/test/merge-strings.test.ts | 15 + .../unminify/test/number-expressions.test.ts | 25 + packages/unminify/test/raw-literals.test.ts | 13 + packages/unminify/test/sequence.test.ts | 104 + packages/unminify/test/setup.ts | 8 + .../test/split-variable-declarations.test.ts | 33 + packages/unminify/test/ternary-to-if.test.ts | 32 + .../unminify/test/unminify-booleans.test.ts | 16 + .../unminify/test/void-to-undefined.test.ts | 15 + packages/unminify/test/yoda.test.ts | 62 + packages/unminify/tsconfig.json | 3 + packages/unminify/vitest.config.ts | 11 + packages/unpack/.eslintrc.cjs | 5 + packages/unpack/package.json | 29 + .../unpack/src}/browserify/bundle.ts | 6 +- .../unpack/src}/browserify/index.ts | 65 +- .../unpack/src}/browserify/module.ts | 6 +- packages/unpack/src/bundle.ts | 90 + packages/unpack/src/index.ts | 41 + packages/unpack/src/matchers.d.ts | 41 + .../unpack/src}/module.ts | 6 +- {src/utils => packages/unpack/src}/path.ts | 41 +- .../unpack/src}/webpack/bundle.ts | 38 +- .../unpack/src}/webpack/esm.ts | 79 +- .../unpack/src}/webpack/getDefaultExport.ts | 34 +- .../unpack/src}/webpack/index.ts | 129 +- .../unpack/src}/webpack/module.ts | 2 +- .../unpack/src}/webpack/varInjection.ts | 20 +- .../test/__snapshots__/unpack.test.ts.snap | 192 +- packages/unpack/test/path.test.ts | 76 + .../unpack/test}/samples/browserify-2.js | 0 .../samples/browserify-webpack-nested.js | 0 .../unpack/test}/samples/browserify.js | 0 .../unpack/test}/samples/webpack-0.11.x.js | 0 .../unpack/test}/samples/webpack-esm.js | 0 .../test}/samples/webpack-jsonp-chunk.js | 0 .../unpack/test}/samples/webpack-object.js | 0 .../test}/samples/webpack-path-traversal.js | 0 .../test}/samples/webpack-var-injection.js | 0 .../unpack/test}/samples/webpack.js | 0 .../unpack/test}/samples/webpack5-esm.js | 0 .../unpack/test}/samples/webpack5-object.js | 0 packages/unpack/test/setup.ts | 8 + packages/unpack/test/unpack.test.ts | 59 + packages/unpack/tsconfig.json | 3 + packages/unpack/vitest.config.ts | 11 + packages/webcrack/.eslintrc.cjs | 6 + packages/webcrack/.gitignore | 1 + packages/webcrack/README.md | 1 + .../webcrack/esbuild.config.js | 14 +- packages/webcrack/package.json | 68 + packages/webcrack/src/cli.ts | 63 + packages/webcrack/src/index.ts | 179 + packages/webcrack/src/matchers.d.ts | 41 + .../babel-plugin-minify-mangle-names.d.ts | 6 +- .../webcrack/src}/transforms/jsx-new.ts | 76 +- .../webcrack/src}/transforms/jsx.ts | 62 +- .../webcrack/src}/transforms/mangle.ts | 15 +- packages/webcrack/src/utils/platform.ts | 3 + packages/webcrack/test/api.test.ts | 42 + packages/webcrack/test/setup.ts | 8 + packages/webcrack/test/transforms.test.ts | 145 + packages/webcrack/tsconfig.build.json | 11 + packages/webcrack/tsconfig.json | 10 + packages/webcrack/vitest.config.ts | 11 + patches/vite-plugin-monaco-editor@1.1.0.patch | 12 + pnpm-lock.yaml | 4942 +++++++++++ pnpm-workspace.yaml | 3 + src/cli.ts | 63 - src/deobfuscator/index.ts | 69 - src/extractor/bundle.ts | 99 - src/extractor/index.ts | 29 - src/index.ts | 169 - src/transforms/mergeElseIf.ts | 30 - src/transforms/unminify.ts | 43 - src/transforms/unminifyBooleans.ts | 31 - src/transforms/void0ToUndefined.ts | 22 - src/utils/ast.ts | 25 - src/utils/generator.ts | 11 - test/api.test.ts | 45 - test/deobfuscator.test.ts | 105 - test/extractor.test.ts | 137 - test/rename.test.ts | 82 - test/setup.ts | 8 - test/transforms.test.ts | 873 -- tsconfig.build.json | 13 - tsconfig.json | 22 - turbo.json | 19 + vitest.config.ts | 14 - vitest.workspace.json | 3 + 233 files changed, 10421 insertions(+), 10374 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.cjs create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/test.yml create mode 100644 .npmrc create mode 100644 .prettierrc create mode 100644 .vscode/settings.json delete mode 100644 LICENSE create mode 100644 apps/docs/package.json create mode 100644 apps/docs/src/.vitepress/config.ts create mode 100644 apps/docs/src/.vitepress/theme/custom.css create mode 100644 apps/docs/src/.vitepress/theme/index.ts create mode 100644 apps/docs/src/assets/webpack-structure.png create mode 100644 apps/docs/src/concepts/deobfuscate.md create mode 100644 apps/docs/src/concepts/jsx.md create mode 100644 apps/docs/src/concepts/unminify.md create mode 100644 apps/docs/src/concepts/unpack.md create mode 100644 apps/docs/src/guide/api.md create mode 100644 apps/docs/src/guide/cli.md create mode 100644 apps/docs/src/guide/introduction.md create mode 100644 apps/docs/src/guide/web.md create mode 100644 apps/docs/src/index.md create mode 100644 apps/docs/tsconfig.json create mode 100644 apps/playground/.eslintrc.cjs create mode 100644 apps/playground/README.md create mode 100644 apps/playground/index.html create mode 100644 apps/playground/package.json create mode 100644 apps/playground/postcss.config.js create mode 100644 apps/playground/public/vite.svg create mode 100644 apps/playground/src/App.tsx create mode 100644 apps/playground/src/_empty.ts create mode 100644 apps/playground/src/assets/solid.svg create mode 100644 apps/playground/src/components/Breadcrumbs.tsx create mode 100644 apps/playground/src/components/DirectoryNode.tsx create mode 100644 apps/playground/src/components/FileNode.tsx create mode 100644 apps/playground/src/components/FileTree.tsx create mode 100644 apps/playground/src/components/MonacoEditor.tsx create mode 100644 apps/playground/src/components/Sidebar.tsx create mode 100644 apps/playground/src/components/Tab.tsx create mode 100644 apps/playground/src/context/DeobfuscateContext.tsx create mode 100644 apps/playground/src/hooks/useTheme.ts create mode 100644 apps/playground/src/index.css create mode 100644 apps/playground/src/index.tsx create mode 100644 apps/playground/src/monaco/eval-selection.ts create mode 100644 apps/playground/src/monaco/placeholder-widget.ts create mode 100644 apps/playground/src/sandbox.ts create mode 100644 apps/playground/src/vite-env.d.ts create mode 100644 apps/playground/src/webcrack.worker.ts create mode 100644 apps/playground/tailwind.config.ts create mode 100644 apps/playground/tsconfig.json create mode 100644 apps/playground/turbo.json create mode 100644 apps/playground/vite.config.ts create mode 100644 apps/web/netlify.toml create mode 100644 apps/web/package.json delete mode 100644 package-lock.json create mode 100644 packages/ast-utils/.eslintrc.cjs create mode 100644 packages/ast-utils/package.json create mode 100644 packages/ast-utils/src/ast.ts create mode 100644 packages/ast-utils/src/generator.ts create mode 100644 packages/ast-utils/src/index.ts rename {src/utils => packages/ast-utils/src}/inline.ts (83%) rename {src/utils => packages/ast-utils/src}/matcher.ts (73%) rename {src => packages/ast-utils/src}/matchers.d.ts (81%) rename {src/utils => packages/ast-utils/src}/rename.ts (76%) rename src/transforms/index.ts => packages/ast-utils/src/transform.ts (57%) create mode 100644 packages/ast-utils/test/rename.test.ts create mode 100644 packages/ast-utils/test/setup.ts create mode 100644 packages/ast-utils/tsconfig.json create mode 100644 packages/ast-utils/vitest.config.ts create mode 100644 packages/config-eslint/index.js create mode 100644 packages/config-eslint/package.json create mode 100644 packages/config-typescript/base.json create mode 100644 packages/config-typescript/package.json create mode 100644 packages/config-typescript/vite.json create mode 100644 packages/deobfuscate/.eslintrc.cjs create mode 100644 packages/deobfuscate/package.json rename src/deobfuscator/arrayRotator.ts => packages/deobfuscate/src/array-rotator.ts (66%) rename src/deobfuscator/controlFlowObject.ts => packages/deobfuscate/src/control-flow-object.ts (84%) rename src/deobfuscator/controlFlowSwitch.ts => packages/deobfuscate/src/control-flow-switch.ts (64%) rename src/deobfuscator/deadCode.ts => packages/deobfuscate/src/dead-code.ts (70%) rename src/deobfuscator/debugProtection.ts => packages/deobfuscate/src/debug-protection.ts (80%) rename {src/deobfuscator => packages/deobfuscate/src}/decoder.ts (81%) create mode 100644 packages/deobfuscate/src/index.ts rename src/deobfuscator/inlineDecodedStrings.ts => packages/deobfuscate/src/inline-decoded-strings.ts (56%) rename src/deobfuscator/inlineDecoderWrappers.ts => packages/deobfuscate/src/inline-decoder-wappers.ts (66%) rename src/deobfuscator/inlineObjectProps.ts => packages/deobfuscate/src/inline-object-props.ts (74%) create mode 100644 packages/deobfuscate/src/matchers.d.ts rename src/deobfuscator/mergeObjectAssignments.ts => packages/deobfuscate/src/merge-object-assignments.ts (85%) rename src/deobfuscator/selfDefending.ts => packages/deobfuscate/src/self-defending.ts (83%) rename src/deobfuscator/stringArray.ts => packages/deobfuscate/src/string-array.ts (83%) rename {src/deobfuscator => packages/deobfuscate/src}/vm.ts (64%) rename test/__snapshots__/deobfuscator.test.ts.snap => packages/deobfuscate/test/__snapshots__/deobfuscate.test.ts.snap (100%) create mode 100644 packages/deobfuscate/test/__snapshots__/deobfuscator.test.ts.snap create mode 100644 packages/deobfuscate/test/deobfuscate.test.ts create mode 100644 packages/deobfuscate/test/index.ts create mode 100644 packages/deobfuscate/test/inline-object-props.test.ts create mode 100644 packages/deobfuscate/test/merge-object-assignments.test.ts rename {test => packages/deobfuscate/test}/samples/obfuscator.io-calls-transform.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-control-flow-keys.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-control-flow-partial-keys.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-control-flow-split-strings.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-control-flow-spread.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-control-flow-switch-return.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-control-flow.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-function-wrapper.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-high.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-multi-encoders.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io-rotator-unary.js (100%) rename {test => packages/deobfuscate/test}/samples/obfuscator.io.js (100%) rename {test => packages/deobfuscate/test}/samples/simple-string-array.js (100%) create mode 100644 packages/deobfuscate/test/setup.ts create mode 100644 packages/deobfuscate/tsconfig.json create mode 100644 packages/deobfuscate/vitest.config.ts create mode 100644 packages/unminify/.eslintrc.cjs create mode 100644 packages/unminify/package.json create mode 100644 packages/unminify/src/index.ts create mode 100644 packages/unminify/src/matchers.d.ts rename src/transforms/blockStatement.ts => packages/unminify/src/transforms/block-statements.ts (89%) rename src/transforms/computedProperties.ts => packages/unminify/src/transforms/computed-properties.ts (66%) create mode 100644 packages/unminify/src/transforms/index.ts rename src/transforms/jsonParse.ts => packages/unminify/src/transforms/json-parse.ts (57%) rename src/transforms/booleanIf.ts => packages/unminify/src/transforms/logical-to-if.ts (77%) create mode 100644 packages/unminify/src/transforms/merge-else-if.ts rename src/transforms/mergeStrings.ts => packages/unminify/src/transforms/merge-strings.ts (73%) rename src/transforms/numberExpressions.ts => packages/unminify/src/transforms/number-expressions.ts (53%) rename src/transforms/rawLiterals.ts => packages/unminify/src/transforms/raw-literals.ts (78%) rename {src => packages/unminify/src}/transforms/sequence.ts (72%) rename src/transforms/splitVariableDeclarations.ts => packages/unminify/src/transforms/split-variable-declarations.ts (57%) rename src/transforms/ternaryToIf.ts => packages/unminify/src/transforms/ternary-to-if.ts (85%) create mode 100644 packages/unminify/src/transforms/unminify-booleans.ts create mode 100644 packages/unminify/src/transforms/void-to-undefined.ts rename {src => packages/unminify/src}/transforms/yoda.ts (60%) create mode 100644 packages/unminify/test/block-statements.test.ts create mode 100644 packages/unminify/test/computed-properties.test.ts create mode 100644 packages/unminify/test/index.ts create mode 100644 packages/unminify/test/json-parse.test.ts create mode 100644 packages/unminify/test/logical-to-if.test.ts create mode 100644 packages/unminify/test/merge-else-if.test.ts create mode 100644 packages/unminify/test/merge-strings.test.ts create mode 100644 packages/unminify/test/number-expressions.test.ts create mode 100644 packages/unminify/test/raw-literals.test.ts create mode 100644 packages/unminify/test/sequence.test.ts create mode 100644 packages/unminify/test/setup.ts create mode 100644 packages/unminify/test/split-variable-declarations.test.ts create mode 100644 packages/unminify/test/ternary-to-if.test.ts create mode 100644 packages/unminify/test/unminify-booleans.test.ts create mode 100644 packages/unminify/test/void-to-undefined.test.ts create mode 100644 packages/unminify/test/yoda.test.ts create mode 100644 packages/unminify/tsconfig.json create mode 100644 packages/unminify/vitest.config.ts create mode 100644 packages/unpack/.eslintrc.cjs create mode 100644 packages/unpack/package.json rename {src/extractor => packages/unpack/src}/browserify/bundle.ts (50%) rename {src/extractor => packages/unpack/src}/browserify/index.ts (74%) rename {src/extractor => packages/unpack/src}/browserify/module.ts (67%) create mode 100644 packages/unpack/src/bundle.ts create mode 100644 packages/unpack/src/index.ts create mode 100644 packages/unpack/src/matchers.d.ts rename {src/extractor => packages/unpack/src}/module.ts (79%) rename {src/utils => packages/unpack/src}/path.ts (61%) rename {src/extractor => packages/unpack/src}/webpack/bundle.ts (63%) rename {src/extractor => packages/unpack/src}/webpack/esm.ts (74%) rename {src/extractor => packages/unpack/src}/webpack/getDefaultExport.ts (78%) rename {src/extractor => packages/unpack/src}/webpack/index.ts (67%) rename {src/extractor => packages/unpack/src}/webpack/module.ts (56%) rename {src/extractor => packages/unpack/src}/webpack/varInjection.ts (70%) rename test/__snapshots__/extractor.test.ts.snap => packages/unpack/test/__snapshots__/unpack.test.ts.snap (80%) create mode 100644 packages/unpack/test/path.test.ts rename {test => packages/unpack/test}/samples/browserify-2.js (100%) rename {test => packages/unpack/test}/samples/browserify-webpack-nested.js (100%) rename {test => packages/unpack/test}/samples/browserify.js (100%) rename {test => packages/unpack/test}/samples/webpack-0.11.x.js (100%) rename {test => packages/unpack/test}/samples/webpack-esm.js (100%) rename {test => packages/unpack/test}/samples/webpack-jsonp-chunk.js (100%) rename {test => packages/unpack/test}/samples/webpack-object.js (100%) rename {test => packages/unpack/test}/samples/webpack-path-traversal.js (100%) rename {test => packages/unpack/test}/samples/webpack-var-injection.js (100%) rename {test => packages/unpack/test}/samples/webpack.js (100%) rename {test => packages/unpack/test}/samples/webpack5-esm.js (100%) rename {test => packages/unpack/test}/samples/webpack5-object.js (100%) create mode 100644 packages/unpack/test/setup.ts create mode 100644 packages/unpack/test/unpack.test.ts create mode 100644 packages/unpack/tsconfig.json create mode 100644 packages/unpack/vitest.config.ts create mode 100644 packages/webcrack/.eslintrc.cjs create mode 100644 packages/webcrack/.gitignore create mode 100644 packages/webcrack/README.md rename esbuild.config.js => packages/webcrack/esbuild.config.js (85%) create mode 100644 packages/webcrack/package.json create mode 100644 packages/webcrack/src/cli.ts create mode 100644 packages/webcrack/src/index.ts create mode 100644 packages/webcrack/src/matchers.d.ts rename {src => packages/webcrack/src}/transforms/babel-plugin-minify-mangle-names.d.ts (52%) rename {src => packages/webcrack/src}/transforms/jsx-new.ts (75%) rename {src => packages/webcrack/src}/transforms/jsx.ts (77%) rename {src => packages/webcrack/src}/transforms/mangle.ts (62%) create mode 100644 packages/webcrack/src/utils/platform.ts create mode 100644 packages/webcrack/test/api.test.ts create mode 100644 packages/webcrack/test/setup.ts create mode 100644 packages/webcrack/test/transforms.test.ts create mode 100644 packages/webcrack/tsconfig.build.json create mode 100644 packages/webcrack/tsconfig.json create mode 100644 packages/webcrack/vitest.config.ts create mode 100644 patches/vite-plugin-monaco-editor@1.1.0.patch create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml delete mode 100644 src/cli.ts delete mode 100644 src/deobfuscator/index.ts delete mode 100644 src/extractor/bundle.ts delete mode 100644 src/extractor/index.ts delete mode 100644 src/index.ts delete mode 100644 src/transforms/mergeElseIf.ts delete mode 100644 src/transforms/unminify.ts delete mode 100644 src/transforms/unminifyBooleans.ts delete mode 100644 src/transforms/void0ToUndefined.ts delete mode 100644 src/utils/ast.ts delete mode 100644 src/utils/generator.ts delete mode 100644 test/api.test.ts delete mode 100644 test/deobfuscator.test.ts delete mode 100644 test/extractor.test.ts delete mode 100644 test/rename.test.ts delete mode 100644 test/setup.ts delete mode 100644 test/transforms.test.ts delete mode 100644 tsconfig.build.json delete mode 100644 tsconfig.json create mode 100644 turbo.json delete mode 100644 vitest.config.ts create mode 100644 vitest.workspace.json diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 7d5bf69a..00000000 --- a/.eslintrc +++ /dev/null @@ -1,41 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true, - "node": true - }, - "ignorePatterns": [ - "dist", - "tmp", - "test/samples", - "test/__snapshots__" - ], - "plugins": [ - "@typescript-eslint" - ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module", - "project": true - }, - "rules": { - "indent": [ - "error", - 2 - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ], - "@typescript-eslint/explicit-module-boundary-types": "error" - } -} diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 00000000..c6082e81 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,6 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], + ignorePaths: ["vitest.config.ts"], +}; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..eddb196c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + +jobs: + build: + name: Build and Test + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} + steps: + - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v2 + - uses: actions/setup-node@v3 + with: + node-version: "18.x" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install + + - name: Lint + run: pnpm lint + + - name: Test + run: pnpm test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b894f079..66845272 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,28 +7,24 @@ on: jobs: build: runs-on: ubuntu-latest + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} steps: - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v2 - uses: actions/setup-node@v3 with: - node-version: '18.x' - registry-url: 'https://registry.npmjs.org' - - - name: Cache node modules - id: nodemodules-cache - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package-lock.json') }} + node-version: "18.x" + cache: "pnpm" - name: Install dependencies - if: steps.nodemodules-cache.outputs.cache-hit != 'true' - run: npm ci + run: pnpm install - - name: build - run: npm run build + - name: Build + run: pnpm build --filter webcrack - - name: Publish package - run: npm publish + - name: Publish + run: pnpm publish --filter webcrack env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index e824e588..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Test - -on: - push: - branches: [master] - pull_request: - -jobs: - test: - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: '18.x' - cache: 'npm' - - - name: Cache node modules - id: nodemodules-cache - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - - name: Install dependencies - if: steps.nodemodules-cache.outputs.cache-hit != 'true' - run: npm ci - - - name: Run tests - run: npm test - - - name: Build - run: npm run build \ No newline at end of file diff --git a/.gitignore b/.gitignore index c526c678..19538358 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,15 @@ +.DS_Store node_modules +.turbo +*.log dist -tmp -.vscode/settings.json +dist-ssr +*.local +.env +.cache +server/dist +public/dist +**/.vitepress/dist/** +**/.vitepress/cache/** coverage +.netlify diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..ded82e2f --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +auto-install-peers = true diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/.vscode/launch.json b/.vscode/launch.json index 2b6da97b..9a4288ab 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,13 +7,13 @@ { "type": "node", "request": "launch", - "name": "Launch Program", - "runtimeExecutable": "npm", + "name": "Deobfuscate tmp file", + "runtimeExecutable": "pnpm", "runtimeArgs": [ "run", - "dev" + "tmp" ], - "cwd": "${workspaceFolder}/tmp", + "cwd": "${workspaceFolder}/packages/webcrack", "outputCapture": "std", "skipFiles": [ "/**" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..44a73ec3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "eslint.workingDirectories": [ + { + "mode": "auto" + } + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f5f21b6..30ccc8b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,44 +2,44 @@ You can directly create a PR if the change is small. Otherwise, please open an issue first to discuss the change. -The `package.json` version shouldn't be changed. - ## Getting Started +This project uses [pnpm](https://pnpm.js.org/) for package management. Please make sure you have it installed before proceeding. + 1. Fork and clone the repo 2. Check out a new branch: `git checkout -b some-feature` -3. Install dependencies: `npm install` +3. Install dependencies: `pnpm install` +4. Test your changes in the playground: `pnpm dev` -## Debugging +## Attach a Debugger -1. Create a directory named `tmp` with `test.js` inside and paste your code -2. Press `F5` in VSCode to build the project and launch the debugger (or run `npm run dev`) +1. Create the file `packages/webcrack/tmp/test.js` and paste your code +2. Press `F5` in VSCode to build the project and launch the debugger The output will be saved in `tmp/webcrack-out`. ## Tests -Run the tests in watch mode with `npm test` (or use the [Vitest](https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer) vscode extension). +Run the tests with `pnpm test`. -If the snapshots are outdated, make sure the changes are correct and update them: +`.toMatchInlineSnapshot()` for new tests will automatically generate the expected output when saved, no need to write it manually. +If the snapshots are outdated, make sure the changes are correct and update them: ![failed snapshot](https://user-images.githubusercontent.com/55899582/219093007-825a5056-38a0-4e8b-8512-b56e20174885.png) -### Types of tests - -- Transforms: add tests in [transforms.test.ts](test/transforms.test.ts) -- Deobfuscator or bundle unpacker: create/modify a [sample script](test/samples) -- Public JS API: add tests in [api.test.ts](test/api.test.ts) +## Linting and Formatting -The samples should be as small as possible, but still representative. +```bash +pnpm lint:fix && pnpm format +``` -## Create a new transform +## Create a new Transform The easiest way to create a new transform is to copy an existing one and modify it. ## Performance Optimizations -### Named visitor keys +### Named Visitor Keys ```diff { @@ -48,7 +48,7 @@ The easiest way to create a new transform is to copy an existing one and modify } ``` -### `noScope` visitors +### `noScope` Visitors May not work in some cases (accessing `path.scope` when the scope hasn't been crawled before). @@ -59,7 +59,7 @@ May not work in some cases (accessing `path.scope` when the scope hasn't been cr } ``` -### Merging visitors +### Merging Visitors To only traverse the AST once and avoid missing nodes based on the order of visitors. @@ -69,7 +69,7 @@ To only traverse the AST once and avoid missing nodes based on the order of visi + applyTransforms(ast, [transformA, transformB]); ``` -### Renaming bindings (variables, functions, ...) +### Renaming Bindings (variables, functions, ...) This also avoids conflicts by first renaming bindings with the name `b` to something else. @@ -79,7 +79,7 @@ This also avoids conflicts by first renaming bindings with the name `b` to somet + renameFast(binding, 'b'); ``` -### Following references instead of traversing the AST +### Following References instead of Traversing the AST For example finding calls to a function `foo` (provided that you already have foo's NodePath): diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 1a6e5d9b..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 j4k0xb - -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. diff --git a/apps/docs/package.json b/apps/docs/package.json new file mode 100644 index 00000000..050d8756 --- /dev/null +++ b/apps/docs/package.json @@ -0,0 +1,17 @@ +{ + "name": "docs", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vitepress dev src", + "build": "vitepress build src", + "preview": "vitepress preview" + }, + "devDependencies": { + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "typescript": "^5.3.2", + "vitepress": "1.0.0-rc.31" + } +} diff --git a/apps/docs/src/.vitepress/config.ts b/apps/docs/src/.vitepress/config.ts new file mode 100644 index 00000000..30a918ee --- /dev/null +++ b/apps/docs/src/.vitepress/config.ts @@ -0,0 +1,60 @@ +import { defineConfig } from "vitepress"; + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "webcrack", + description: "Deobfuscate, unminify and unpack bundled javascript", + base: "/docs/", + outDir: "../dist/docs", + head: [ + [ + "link", + { + rel: "icon", + href: "https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png", + }, + ], + ], + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + logo: "https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png", + nav: [ + { text: "Home", link: "/" }, + { text: "Guide", link: "/guide/introduction" }, + { text: "Playground", link: "https://webcrack.netlify.app" }, + ], + + sidebar: [ + { + text: "Guide", + items: [ + { text: "Introduction", link: "/guide/introduction" }, + { text: "CLI", link: "/guide/cli" }, + { text: "Node.js API", link: "/guide/api" }, + { text: "Website", link: "/guide/web" }, + ], + }, + { + text: "Concepts", + items: [ + { text: "Deobfuscation", link: "/concepts/deobfuscate" }, + { text: "Unminifying", link: "/concepts/unminify" }, + { text: "Bundle Unpacking", link: "/concepts/unpack" }, + { text: "JSX", link: "/concepts/jsx" }, + ], + }, + ], + + socialLinks: [ + { icon: "github", link: "https://github.com/j4k0xb/webcrack" }, + ], + + search: { + provider: "local", + }, + + editLink: { + pattern: "https://github.com/j4k0xb/webcrack-ui/edit/master/docs/:path", + }, + }, +}); diff --git a/apps/docs/src/.vitepress/theme/custom.css b/apps/docs/src/.vitepress/theme/custom.css new file mode 100644 index 00000000..65abb6e5 --- /dev/null +++ b/apps/docs/src/.vitepress/theme/custom.css @@ -0,0 +1,14 @@ +:root { + --vp-c-brand: #409eea; + --vp-c-brand-1: #409eea; + --vp-c-brand-light: #2d8bd8; + --vp-c-brand-lighter: #6cb5f1; + --vp-button-brand-bg: #409eea; + --vp-button-brand-hover-bg: #1f73b9; + --vp-home-hero-name-color: #409eea; + + --vp-c-brand-dark: #1f73b9; + --vp-c-brand-darker: #1362a3; + + --vp-local-search-highlight-bg: #6cb5f1; +} diff --git a/apps/docs/src/.vitepress/theme/index.ts b/apps/docs/src/.vitepress/theme/index.ts new file mode 100644 index 00000000..0c314338 --- /dev/null +++ b/apps/docs/src/.vitepress/theme/index.ts @@ -0,0 +1,6 @@ +import DefaultTheme from "vitepress/theme"; +import "./custom.css"; + +export default { + ...DefaultTheme, +}; diff --git a/apps/docs/src/assets/webpack-structure.png b/apps/docs/src/assets/webpack-structure.png new file mode 100644 index 0000000000000000000000000000000000000000..42b720c17955f41b9b9e5ed89d3398bf46e5c845 GIT binary patch literal 184707 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 literal 0 HcmV?d00001 diff --git a/apps/docs/src/concepts/deobfuscate.md b/apps/docs/src/concepts/deobfuscate.md new file mode 100644 index 00000000..b4826540 --- /dev/null +++ b/apps/docs/src/concepts/deobfuscate.md @@ -0,0 +1,28 @@ +# Deobfuscation + +## javascript-obfuscator + +The most popular obfuscator ([GitHub](https://github.com/javascript-obfuscator/javascript-obfuscator), [obfuscator.io](https://obfuscator.io)). + +webcrack can deobfuscate code obfuscated with the following options (pretty much all available ones): + +- String Array + - Rotate + - Shuffle + - Index Shift + - Calls Transform + - Variable/Function Wrapper Type + - None/Base64/RC4 Encoding + - Split Strings + - Unicode Escape Sequence +- Other Transformations + - Compact + - Simplify + - Numbers To Expressions + - Control Flow Flattening + - Dead Code Injection + - Transform Object Keys +- Disable Console Output +- Self Defending +- Debug Protection +- Domain Lock diff --git a/apps/docs/src/concepts/jsx.md b/apps/docs/src/concepts/jsx.md new file mode 100644 index 00000000..1484215a --- /dev/null +++ b/apps/docs/src/concepts/jsx.md @@ -0,0 +1,25 @@ +# JSX + +Tools such as [Babel](https://babeljs.io/), [TypeScript](https://www.typescriptlang.org/) +or bundlers convert JSX to `React.createElement` calls. +This feature does the opposite. + +```jsx +React.createElement( + "div", + null, + React.createElement("span", null, "Hello ", name), +); +``` + +-> + +```jsx +
+ Hello {name} +
+``` + +:::info +This currently only works for the React **UMD** build, not when bundled. +::: diff --git a/apps/docs/src/concepts/unminify.md b/apps/docs/src/concepts/unminify.md new file mode 100644 index 00000000..2064b361 --- /dev/null +++ b/apps/docs/src/concepts/unminify.md @@ -0,0 +1,20 @@ +# Unminify + +Bundlers and obfuscators commonly minify code (remove new lines and whitespace, replace variable names with shorter ones, use a shorter syntax). + +Most unminify sites just format the code, but webcrack also converts the syntax back to make it more readable and similar to the original code: + +```js +console["\x6c\x6f\x67"]("\x61"); // console.log('a') +x && y && z(); // if (x && y) z(); +x || y || z(); // if (!(x || y)) z(); +!0; // true +!1; // false +![]; // false +!![]; // true +return a(), b(), c(); // a(); b(); return c(); +if ((a(), b())) c(); // a(); if (b()) c(); +void 0; // undefined +"red" === color; // color === 'red' +JSON.parse('{"a":1}'); // { a: 1 } +``` diff --git a/apps/docs/src/concepts/unpack.md b/apps/docs/src/concepts/unpack.md new file mode 100644 index 00000000..bfa16428 --- /dev/null +++ b/apps/docs/src/concepts/unpack.md @@ -0,0 +1,132 @@ +# Bundle Unpacking + +This feature can unpack [webpack](https://webpack.js.org/) and [browserify](https://browserify.org/) bundles into separate files. + +## Webpack + +- `__webpack_require(id)__` gets rewritten to `require('./relative/path.js')`. + +- Modules may get converted to ESM. + +- multiple chunks are not supported _yet_. + +![Webpack structure](../assets/webpack-structure.png) + + + + + +### `__webpack_require__` + +```ts +/** + * Most of the time this is an object for multiple exports, + * but a module can export anything + */ +type Exports = unknown; + +/** + * Each module is wrapped in a factory function to give it access to these arguments like they were global variables + */ +type FactoryFunction = ( + module: Module, + exports: Exports, + __webpack_require__: WebpackRequire, +) => void; + +interface Module { + exports: Exports; // module exports + i: number; // module id + l: boolean; // loaded +} +``` + +`__webpack_require__` is a function with some additional properties: + +```ts +interface WebpackRequire { + // Call to load a module + (moduleId: number): Exports; + // Define getter functions for esm exports + d(exports: Exports, name: string, getter: () => Exports): void; + // Load a chunk + e(chunkId: number): Promise; + // Returns globalThis or window + g(): typeof globalThis; + // loadScript function to load a script via script tag + l( + url: string, + done: (event: Event) => void, + key: string | undefined, + chunkId: number, + ): void; + // Get the default export of a module, for compatibility with non-esm + n(exports: Exports): { (): Exports; get a(): Exports }; + // Object.prototype.hasOwnProperty.call + o(object: unknown, property: string): boolean; + // On error function for async loading + oe(err: Error): never; + // Set __esModule to true + r(exports: Exports): void; + // Create a fake namespace object + t(value: number | Record, mode: number): unknown; + // Get javascript chunk filename. Example: u(0) -> 'chunks/0.138aa346.js' + u(chunkId: number): string; + + // Contains all installed modules. The keys are module ids + c: Record; + f: { + // JSONP chunk loading for javascript + j(chunkId: number, promises: Promise[]): void; + }; + // Contains all module functions. The keys are module ids + m: Record; + // Public base path for chunks. Example: '/_next/' + p: string; + // Entry module id + s: number; + // All WebAssembly.instance exports. The keys are wasm module ids + w: Record; +} +``` + + + +## Browserify + +Each module has a numerical id and contains a list of dependencies: `{ './foo': 1, './bar': 3 }`. +These paths are relative to the current module and are used like `require('./foo')`. + +The absolute path a module is not stored anywhere, so webcrack builds a dependency tree +and resolves the paths to preserve the original file structure as much as possible. + +::: details Example + +Module id -> dependencies: + +```js +{ + 0: { 1: './a.js', 4: 'lib' }, // entry + 1: { 2: '../bar/b.js' }, + 2: { 3: '../../c.js' }, + 3: {}, + 4: {}, +} +``` + +Resulting file structure: + +```txt +├── tmp0 +│ ├── tmp1 +│ │ ├── index.js +│ │ └── a.js +│ └── bar +│ └── b.js +├── c.js +``` + +::: + +Sometimes the entry module was deeply nested (e.g. `src/app/index.js`), but `"src"` or `"app"` is not included in the bundle. +In this case, directory names like `tmp0/tmp1`, etc. are used instead. diff --git a/apps/docs/src/guide/api.md b/apps/docs/src/guide/api.md new file mode 100644 index 00000000..60f8297e --- /dev/null +++ b/apps/docs/src/guide/api.md @@ -0,0 +1,92 @@ +# API Examples + +:::info +This is a pure ESM package, so you need to use `import` instead of `require`. +For more info, check out [this gist](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). +::: + +```bash +npm install webcrack +``` + +## Basic Usage + +```js +import { webcrack } from "webcrack"; + +const result = await webcrack("const a = 1+1;"); +console.log(result.code); // 'const a = 2;' +``` + +Save the deobufscated code and the unpacked bundle to the given directory: + +```js +import fs from "fs"; +import { webcrack } from "webcrack"; + +const code = fs.readFileSync("bundle.js", "utf8"); +const result = await webcrack(code); +await result.save("output-dir"); +``` + +## Get Bundle Info + +```js +const { bundle } = await webcrack(code); +bundle.type; // 'webpack' or 'browserify' +bundle.entryId; // '0' +bundle.modules; // Map(10) { '0' => Module { id: '0', ... }, 1 => ... } + +const entry = bundle.modules.get(bundle.entryId); +entry.id; // '0' +entry.path; // './index.js' +entry.code; // 'const a = require("./1.js");' +``` + +## Options + +The default options are: + +```js +await webcrack(code, { + jsx: true, // Decompile react components to JSX + unpack: true, // Extract modules from the bundle + deobfuscate: true, // Deobfuscate the code + mangle: false, // Mangle variable names +}); +``` + +## Customize Paths + +Useful for reverse-engineering and tracking changes across multiple versions of a bundle. + +If a matching node in the AST of a module is found, it will be renamed to the given path. + +- Path starting with `./` are relative to the output directory. +- Otherwise, the path is treated as a node module. + +```js +const result = await webcrack(code, { + mappings: (m) => ({ + "./utils/color.js": m.regExpLiteral("^#([0-9a-f]{3}){1,2}$"), + "lodash/index.js": m.memberExpression( + m.identifier("lodash"), + m.identifier("map"), + ), + }), +}); +await result.save("output-dir"); +``` + +New folder structure: + +```txt +├── index.js +├── utils +│ └── color.js +└── node_modules + └── lodash + └── index.js +``` + +See [@codemod/matchers](https://github.com/codemod-js/codemod/tree/main/packages/matchers#readme) for more information about matchers. diff --git a/apps/docs/src/guide/cli.md b/apps/docs/src/guide/cli.md new file mode 100644 index 00000000..99845f82 --- /dev/null +++ b/apps/docs/src/guide/cli.md @@ -0,0 +1,61 @@ +# Command Line Interface + +Install the package globally: + +```bash +npm install -g webcrack +``` + +```txt +Usage: webcrack [options] [file] + +Arguments: + file input file, defaults to stdin + +Options: + -V, --version output the version number + -o, --output output directory for bundled files + -f, --force overwrite output directory + -m, --mangle mangle variable names + -h, --help display help for command +``` + +The code can be passed as a file or via stdin: + +```bash +webcrack input.js +# or download/pipe a script from a website +curl https://pastebin.com/raw/ye3usFvH | webcrack +``` + +By default it outputs debug logs and the deobfuscated/unminified code to the terminal. +To write the code to a file, you can do: + +```bash +webcrack input.js > output.js +``` + +## Bundle Unpacking + +Use the `-o` option to unpack a bundle into a directory: + +```bash +webcrack bundle.js -o output +``` + +The output directory will contain the following files: + +- `deobfuscated.js` - deobfuscated/unminified code +- `bundle.json` - bundle type and module ids/paths +- `index.js` - entry point +- all remaining modules (`1.js`, `2.js`, etc.) + +::: tip +You can modify the unpacked modules and bundle them again: + +```bash +npx webpack-cli ./output/index.js +``` + +Depending on how the bundle was created, you may need a custom [webpack config](https://webpack.js.org/configuration). +::: diff --git a/apps/docs/src/guide/introduction.md b/apps/docs/src/guide/introduction.md new file mode 100644 index 00000000..60b5b979 --- /dev/null +++ b/apps/docs/src/guide/introduction.md @@ -0,0 +1,33 @@ +# Introduction + +webcrack is a tool for reverse engineering javascript. +It can deobfuscate [obfuscator.io](https://github.com/javascript-obfuscator/javascript-obfuscator), unminify, +and unpack [webpack](https://webpack.js.org/)/[browserify](https://browserify.org/), +to resemble the original source code as much as possible. + +- 🚀 **Performance** - 500% faster than [synchrony](https://github.com/relative/synchrony) +- 🛡️ **Safety** - Considers variable references and scope +- 🔬 **Auto-detection** - Finds code patterns without needing a config +- ✍🏻 **Readability** - Removes obfuscator/bundler artifacts +- ⌨️ **TypeScript** - All code is written in TypeScript +- 🧪 **Tests** - To make sure nothing breaks + +## Platforms + +| Platform | Deobfuscate | Unminify | Unpack | Configurable | +| -------- | ----------- | -------- | ------ | ------------ | +| node | ✅ | ✅ | ✅ | ✅ | +| cli | ✅ | ✅ | ✅ | 🚧 | +| web | ✅ | ✅ | ✅ | 🚧 | + +🚧: only the `mangle` option can be toggled as of now + +## Planned Features + +- support older obfuscator.io versions +- unpack `rollup`, `parcel`, `swc`, etc. +- unpack multi-chunk bundles +- download zip of all unpacked modules in the playground +- convert [@babel/preset-env](https://babeljs.io/docs/babel-preset-env) helpers to modern syntax +- decompile typescript enums +- decompile other frontend frameworks: `vue`, `svelte`, etc. diff --git a/apps/docs/src/guide/web.md b/apps/docs/src/guide/web.md new file mode 100644 index 00000000..85c94ee3 --- /dev/null +++ b/apps/docs/src/guide/web.md @@ -0,0 +1,34 @@ +# Website + +On the [playground](https://webcrack.netlify.app/) you can deobfuscate code without installing anything. +It runs entirely in the browser, so the code never leaves your computer. + +::: tip + +- Press `F1` to open the command palette +- Press `Alt`+`Enter` to run webcrack on the code +- Press `Shift`+`Enter` to evaluate and replace the selected code as a value (`[[3+4]][0]` -> `[7]`) +- Press `Ctrl`+`Shift`+`Enter` to evaluate and replace the selected code raw (`'x' + ' = \'val\''` -> `x = 'val'` instead of a string) +- Press `Ctrl`+`S` to download the code + +::: + +## Query Parameters + +Pass either `code` or `url` parameters to load code into the editor. +Keep in mind to encode them (e.g. `encodeURIComponent` in js). + +| Parameter | Description | +| --------- | -------------------------------------------- | +| `code` | Code as a string (max length: ~16,000) | +| `url` | URL to fetch code from | +| `run` | Automatically start deobfuscation (optional) | + +Examples: + +- [/?code=1-1&run](https://webcrack.netlify.app/?code=1-1&run) +- [/?url=https://pastebin.com/raw/ye3usFvH](https://webcrack.netlify.app/?url=https%3A%2F%2Fpastebin.com%2Fraw%2Fye3usFvH) + +::: info +Use this only if you don't mind netlify or corsproxy.io seeing the code/url, otherwise paste it directly into the editor. +::: diff --git a/apps/docs/src/index.md b/apps/docs/src/index.md new file mode 100644 index 00000000..06dd505d --- /dev/null +++ b/apps/docs/src/index.md @@ -0,0 +1,27 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home +title: Documentation + +hero: + name: "webcrack" + logo: https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png + actions: + - theme: brand + text: Get Started + link: /guide/introduction + - theme: alt + text: Open Playground + link: https://webcrack.netlify.app + +features: + - title: Deobfuscate + details: Undo all the obfuscation techniques of
obfuscator.io + icon: 🛡️ + - title: Unminify + details: Convert minified code to human readable code + icon: 🧹 + - title: Unpack Bundles + details: Extract modules from webpack and browserify bundles to separate files + icon: 📦 +--- diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json new file mode 100644 index 00000000..a1c2a576 --- /dev/null +++ b/apps/docs/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@webcrack/typescript-config/vite.json", + "include": [ + "src" + ] +} diff --git a/apps/playground/.eslintrc.cjs b/apps/playground/.eslintrc.cjs new file mode 100644 index 00000000..d0f2c30e --- /dev/null +++ b/apps/playground/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], +}; diff --git a/apps/playground/README.md b/apps/playground/README.md new file mode 100644 index 00000000..b9a7c751 --- /dev/null +++ b/apps/playground/README.md @@ -0,0 +1 @@ +# `playground` diff --git a/apps/playground/index.html b/apps/playground/index.html new file mode 100644 index 00000000..473d7b33 --- /dev/null +++ b/apps/playground/index.html @@ -0,0 +1,16 @@ + + + + + + + + webcrack + + + +
+ + + + diff --git a/apps/playground/package.json b/apps/playground/package.json new file mode 100644 index 00000000..00d1f6f6 --- /dev/null +++ b/apps/playground/package.json @@ -0,0 +1,36 @@ +{ + "name": "playground", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint src", + "lint:fix": "eslint src --fix" + }, + "devDependencies": { + "@types/babel__generator": "^7.6.7", + "@types/node": "^20.10.1", + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "autoprefixer": "^10.4.16", + "daisyui": "^4.4.17", + "postcss": "^8.4.31", + "tailwindcss": "^3.3.5", + "typescript": "^5.3.2", + "vite": "^4.5.0", + "vite-plugin-monaco-editor": "^1.1.0", + "vite-plugin-node-polyfills": "^0.16.0", + "vite-plugin-solid": "^2.7.2" + }, + "dependencies": { + "@babel/generator": "^7.23.5", + "@babel/types": "^7.23.5", + "monaco-editor": "^0.44.0", + "sandybox": "^1.1.2", + "solid-js": "^1.8.6", + "webcrack": "workspace:*" + } +} diff --git a/apps/playground/postcss.config.js b/apps/playground/postcss.config.js new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/apps/playground/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/apps/playground/public/vite.svg b/apps/playground/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/apps/playground/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/playground/src/App.tsx b/apps/playground/src/App.tsx new file mode 100644 index 00000000..4405837e --- /dev/null +++ b/apps/playground/src/App.tsx @@ -0,0 +1,183 @@ +import * as monaco from "monaco-editor"; +import { For, Show, createMemo, createSignal, onCleanup } from "solid-js"; +import { createStore } from "solid-js/store"; +import Breadcrumbs from "./components/Breadcrumbs"; +import MonacoEditor from "./components/MonacoEditor"; +import Sidebar from "./components/Sidebar"; +import Tab from "./components/Tab"; +import { DeobfuscateContextProvider } from "./context/DeobfuscateContext"; +import { DeobfuscateResult } from "./webcrack.worker"; + +export const [settings, setSettings] = createStore({ + mangle: false, + deobfuscate: true, + jsx: true, + unpack: true, +}); + +function App() { + const [untitledCounter, setUntitledCounter] = createSignal(1); + const [models, setModels] = createSignal([ + monaco.editor.createModel( + "", + "javascript", + monaco.Uri.from({ scheme: "untitled", path: "Untitled-1" }), + ), + ]); + const [tabs, setTabs] = createSignal(models()); + const [activeTab, setActiveTab] = createSignal< + monaco.editor.ITextModel | undefined + >(tabs()[0]); + + const fileModels = createMemo(() => + models().filter((m) => m.uri.scheme === "file"), + ); + const untitledModels = createMemo(() => + models().filter((m) => m.uri.scheme === "untitled"), + ); + const filePaths = createMemo(() => + fileModels().map((model) => model.uri.fsPath), + ); + + onCleanup(() => { + models().forEach((model) => model.dispose()); + }); + + function openTab(tab: monaco.editor.ITextModel) { + if (!tabs().includes(tab)) { + setTabs([...tabs(), tab]); + } + setActiveTab(tab); + } + + function openFile(path: string) { + const model = fileModels().find((m) => m.uri.fsPath === "/" + path); + if (!model) { + return console.warn(`No model found for path: ${path}`); + } + openTab(model); + } + + function closeTab(tab: monaco.editor.ITextModel) { + const index = tabs().indexOf(tab); + if (activeTab() === tab) { + setActiveTab(tabs()[index > 0 ? index - 1 : 1]); + } + setTabs(tabs().filter((t) => t !== tab)); + if (tab.uri.scheme === "untitled") { + tab.dispose(); + // FIXME: resets folder expansion state + setModels(models().filter((m) => m !== tab)); + } + } + + function openUntitledTab() { + setUntitledCounter(untitledCounter() + 1); + const model = monaco.editor.createModel( + "", + "javascript", + monaco.Uri.from({ + scheme: "untitled", + path: `Untitled-${untitledCounter()}`, + }), + ); + setModels([...models(), model]); + openTab(model); + return model; + } + + function onDeobfuscateResult(result: DeobfuscateResult) { + let model = activeTab(); + + if (result.files.length === 0) { + model ||= openUntitledTab(); + model.setValue(result.code); + return; + } + + if (!model || model.uri.scheme === "file") { + model = openUntitledTab(); + } + + model.setValue(result.code); + + // Dispose previous file models + fileModels().forEach((model) => model.dispose()); + setTabs(untitledModels()); + + setModels([ + ...untitledModels(), + ...result.files.map((file) => + monaco.editor.createModel( + file.code, + "javascript", + monaco.Uri.file(file.path), + ), + ), + monaco.editor.createModel( + result.code, + "javascript", + monaco.Uri.file("deobfuscated.js"), + ), + ]); + } + + function onDeobfuscateError(error: unknown) { + console.error(error); + } + + return ( + +
+ + +
+
+ + {(tab) => ( + setActiveTab(tab)} + onClose={() => closeTab(tab)} + /> + )} + +
+ + + + + +
+
+ + + + + +
+
+
+ ); +} + +export default App; diff --git a/apps/playground/src/_empty.ts b/apps/playground/src/_empty.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/apps/playground/src/_empty.ts @@ -0,0 +1 @@ +export {}; diff --git a/apps/playground/src/assets/solid.svg b/apps/playground/src/assets/solid.svg new file mode 100644 index 00000000..025aa303 --- /dev/null +++ b/apps/playground/src/assets/solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/playground/src/components/Breadcrumbs.tsx b/apps/playground/src/components/Breadcrumbs.tsx new file mode 100644 index 00000000..003b153e --- /dev/null +++ b/apps/playground/src/components/Breadcrumbs.tsx @@ -0,0 +1,18 @@ +import { Index } from "solid-js"; + +interface Props { + path: string; +} + +export default function Breadcrumbs(props: Props) { + const parts = () => props.path.replace(/^\.?\//, "").split("/"); + + return ( + + ); +} diff --git a/apps/playground/src/components/DirectoryNode.tsx b/apps/playground/src/components/DirectoryNode.tsx new file mode 100644 index 00000000..50980809 --- /dev/null +++ b/apps/playground/src/components/DirectoryNode.tsx @@ -0,0 +1,49 @@ +import { For, Show } from "solid-js"; +import FileNode from "./FileNode"; +import { TreeNode } from "./FileTree"; + +interface Props extends TreeNode { + onFileClick?: (node: TreeNode) => void; +} + +export default function DirectoryNode(props: Props) { + return ( +
  • +
    + + + + + + {props.name} + +
      + + {(node) => ( + props.onFileClick?.(node)} + {...node} + /> + } + > + props.onFileClick?.(node)} + {...node} + /> + + )} + +
    +
    +
  • + ); +} diff --git a/apps/playground/src/components/FileNode.tsx b/apps/playground/src/components/FileNode.tsx new file mode 100644 index 00000000..8241fd58 --- /dev/null +++ b/apps/playground/src/components/FileNode.tsx @@ -0,0 +1,26 @@ +import { TreeNode } from "./FileTree"; + +interface Props extends TreeNode { + onClick?: () => void; +} + +export default function FileNode(props: Props) { + function handleClick(event: Event) { + event.stopPropagation(); + props.onClick?.(); + } + + return ( +
  • + + + + + {props.name} + +
  • + ); +} diff --git a/apps/playground/src/components/FileTree.tsx b/apps/playground/src/components/FileTree.tsx new file mode 100644 index 00000000..6519e177 --- /dev/null +++ b/apps/playground/src/components/FileTree.tsx @@ -0,0 +1,107 @@ +import { For, Show } from "solid-js"; +import DirectoryNode from "./DirectoryNode"; +import FileNode from "./FileNode"; + +export interface TreeNode { + path: string; + name: string; + isDirectory: boolean; + children: TreeNode[]; +} + +interface Props { + paths: string[]; + onFileClick?: (node: TreeNode) => void; +} + +export default function FileTree(props: Props) { + const items = () => generateTreeNodes(props.paths); + + return ( + + ); +} + +function generateTreeNodes(paths: string[]): TreeNode[] { + const tree: TreeNode[] = []; + const treeCache = new Map(); + + sortPathsTokens(paths).forEach((tokens) => { + let currentLevel = tree; + + tokens.forEach((token, i) => { + const existingPath = treeCache.get(token); + + if (existingPath) { + currentLevel = existingPath.children; + } else { + const subtree: TreeNode = { + name: token, + path: tokens.slice(0, i + 1).join("/"), + isDirectory: i < tokens.length - 1, + children: [], + }; + + treeCache.set(token, subtree); + currentLevel.push(subtree); + currentLevel = subtree.children; + } + }); + }); + + return tree; +} + +// Based on https://github.com/ghornich/sort-paths +function sortPathsTokens(paths: string[]): string[][] { + const collator = new Intl.Collator(undefined, { + numeric: true, + sensitivity: "base", + }); + + return paths + .map((path) => path.replace(/^\//, "").split("/")) + .sort((a, b) => { + const maxDepth = Math.max(a.length, b.length); + for (let depth = 0; depth < maxDepth; depth++) { + if (depth >= a.length) { + return -1; + } else if (depth >= b.length) { + return 1; + } + + const aToken = a[depth]; + const bToken = b[depth]; + if (aToken === bToken) { + continue; + } + + const aIsDir = depth < a.length - 1; + const bIsDir = depth < b.length - 1; + + if (aIsDir === bIsDir) { + return collator.compare(aToken, bToken); + } else { + return aIsDir ? -1 : 1; + } + } + + return -1; + }); +} diff --git a/apps/playground/src/components/MonacoEditor.tsx b/apps/playground/src/components/MonacoEditor.tsx new file mode 100644 index 00000000..2ed127e1 --- /dev/null +++ b/apps/playground/src/components/MonacoEditor.tsx @@ -0,0 +1,124 @@ +// TODO: run babel in the worker instead to avoid bundling it 2x +import * as monaco from "monaco-editor"; +import { createEffect, onCleanup, onMount } from "solid-js"; +import { useDeobfuscateContext } from "../context/DeobfuscateContext"; +import { useTheme } from "../hooks/useTheme"; +import { registerEvalSelection } from "../monaco/eval-selection"; +import { PlaceholderContentWidget } from "../monaco/placeholder-widget"; + +interface Props { + models: monaco.editor.ITextModel[]; + currentModel?: monaco.editor.ITextModel; + onModelChange?: (model: monaco.editor.ITextModel) => void; +} + +monaco.editor.defineTheme("dark", { + base: "vs-dark", + inherit: true, + rules: [], + colors: { "editor.background": "#1b1b1f" }, +}); + +export default function MonacoEditor(props: Props) { + const { deobfuscate, deobfuscating } = useDeobfuscateContext(); + const [theme] = useTheme(); + const viewStates = new WeakMap< + monaco.editor.ITextModel, + monaco.editor.ICodeEditorViewState + >(); + let container: HTMLDivElement | undefined; + + onMount(() => { + const editor = monaco.editor.create(container!, { + language: "javascript", + automaticLayout: true, + wordWrap: "on", + }); + + createEffect(() => { + setModel(props.currentModel); + }); + + createEffect(() => { + monaco.editor.setTheme(theme()); + }); + + createEffect(() => { + // TODO: only update current model, or model where the deobfuscation started from + // + editor.updateOptions({ readOnly: deobfuscating() }); + }); + + function setModel(model?: monaco.editor.ITextModel) { + const currentModel = editor.getModel(); + if (currentModel) viewStates.set(currentModel, editor.saveViewState()!); + editor.setModel(model ?? null); + if (model) editor.restoreViewState(viewStates.get(model) ?? null); + editor.focus(); + } + + // Go to definition + const editorOpener = monaco.editor.registerEditorOpener({ + openCodeEditor(_source, resource, selectionOrPosition) { + const newModel = props.models.find( + (model) => model.uri.path === resource.path, + ); + if (!newModel) return false; + + setModel(newModel); + + if (monaco.Range.isIRange(selectionOrPosition)) { + editor.revealRangeInCenterIfOutsideViewport(selectionOrPosition); + editor.setSelection(selectionOrPosition); + } else if (monaco.Selection.isISelection(selectionOrPosition)) { + editor.revealPositionInCenterIfOutsideViewport(selectionOrPosition); + editor.setPosition(selectionOrPosition); + } + + props.onModelChange?.(newModel); + + return true; + }, + }); + + // Enable IntelliSense for multiple files + monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true); + + const placeholder = new PlaceholderContentWidget( + "// Paste your obfuscated or bundled code here", + editor, + ); + + const deobfuscateAction = editor.addAction({ + id: "editor.action.deobfuscate", + label: "Deobfuscate", + keybindings: [monaco.KeyMod.Alt | monaco.KeyCode.Enter], + run() { + deobfuscate(); + }, + }); + + const evalAction = registerEvalSelection(editor); + + const commandPalette = editor.getAction("editor.action.quickCommand")!; + editor.addCommand( + monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyP, + () => void commandPalette.run(), + ); + + onCleanup(() => { + editorOpener.dispose(); + placeholder.dispose(); + deobfuscateAction.dispose(); + evalAction.dispose(); + }); + }); + + return ( +
    + ); +} diff --git a/apps/playground/src/components/Sidebar.tsx b/apps/playground/src/components/Sidebar.tsx new file mode 100644 index 00000000..b424637a --- /dev/null +++ b/apps/playground/src/components/Sidebar.tsx @@ -0,0 +1,233 @@ +import { Show, createEffect, createSignal } from "solid-js"; +import { setSettings, settings } from "../App"; +import { useDeobfuscateContext } from "../context/DeobfuscateContext"; +import { useTheme } from "../hooks/useTheme"; +import FileTree from "./FileTree"; + +interface Props { + paths: string[]; + onFileClick?: (path: string) => void; +} + +export default function Sidebar(props: Props) { + const { deobfuscate, deobfuscating, cancelDeobfuscate, progress } = + useDeobfuscateContext(); + const [theme, setTheme] = useTheme(); + const [progressShown, setProgressShown] = createSignal(false); + + createEffect(() => { + if (deobfuscating()) setProgressShown(true); + else if (progress() === 100) setTimeout(() => setProgressShown(false), 500); + else setProgressShown(false); + }); + + return ( + + ); +} diff --git a/apps/playground/src/components/Tab.tsx b/apps/playground/src/components/Tab.tsx new file mode 100644 index 00000000..46586b43 --- /dev/null +++ b/apps/playground/src/components/Tab.tsx @@ -0,0 +1,31 @@ +import { basename } from "path"; + +interface Props { + path: string; + active?: boolean; + onClick?: () => void; + onClose?: () => void; +} + +export default function Tab(props: Props) { + return ( + + {basename(props.path)} + + + ); +} diff --git a/apps/playground/src/context/DeobfuscateContext.tsx b/apps/playground/src/context/DeobfuscateContext.tsx new file mode 100644 index 00000000..1cc2be0b --- /dev/null +++ b/apps/playground/src/context/DeobfuscateContext.tsx @@ -0,0 +1,87 @@ +import { ParentProps, createContext, createSignal, useContext } from "solid-js"; +import type { Options } from "webcrack"; +import { evalCode } from "../sandbox"; +import { + DeobfuscateResult, + WorkerRequest, + WorkerResponse, +} from "../webcrack.worker"; +import WebcrackWorker from "../webcrack.worker?worker"; + +let worker = new WebcrackWorker(); + +const postMessage = (message: WorkerRequest) => worker.postMessage(message); + +function useProviderValue(props: Props) { + const [deobfuscating, setDeobfuscating] = createSignal(false); + const [progress, setProgress] = createSignal(0); + + function cancelDeobfuscate() { + if (!deobfuscating()) return console.warn("Not deobfuscating..."); + + setDeobfuscating(false); + worker.terminate(); + worker = new WebcrackWorker(); + } + + function deobfuscate() { + if (deobfuscating()) return console.warn("Already deobfuscating..."); + if (!props.code) return console.warn("No code to deobfuscate..."); + + setProgress(0); + setDeobfuscating(true); + postMessage({ + type: "deobfuscate", + code: props.code, + options: props.options, + }); + + worker.onmessage = ({ data }: MessageEvent) => { + if (data.type === "sandbox") { + evalCode(data.code) + .then((result) => postMessage({ type: "sandbox", result })) + .catch((error) => { + cancelDeobfuscate(); + props.onError(error); + }); + } else if (data.type === "progress") { + setProgress(data.value); + } else if (data.type === "result") { + setDeobfuscating(false); + props.onResult(data); + } else if (data.type === "error") { + setDeobfuscating(false); + props.onError(data.error); + } + }; + } + + return { + deobfuscating, + cancelDeobfuscate, + deobfuscate, + progress, + }; +} + +const DeobfuscateContext = createContext>(); + +interface Props { + code: string | undefined; + options: Options; + onResult: (result: DeobfuscateResult) => void; + onError: (error: unknown) => void; +} + +export function DeobfuscateContextProvider(props: ParentProps) { + const value = useProviderValue(props); + return ( + + {props.children} + + ); +} + +export function useDeobfuscateContext() { + return useContext(DeobfuscateContext)!; +} diff --git a/apps/playground/src/hooks/useTheme.ts b/apps/playground/src/hooks/useTheme.ts new file mode 100644 index 00000000..f73cf142 --- /dev/null +++ b/apps/playground/src/hooks/useTheme.ts @@ -0,0 +1,31 @@ +import { createEffect, createRoot, createSignal } from "solid-js"; + +type Theme = "dark" | "light"; + +const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); +const preferredTheme = darkMediaQuery.matches ? "dark" : "light"; +const savedTheme = localStorage.getItem("theme") as Theme | null; + +const [theme, setTheme] = createSignal(savedTheme ?? preferredTheme); + +createRoot(() => { + createEffect(() => { + document.documentElement.dataset.theme = theme(); + }); + + darkMediaQuery.addEventListener("change", (event) => { + if (savedTheme === null) { + setTheme(event.matches ? "dark" : "light"); + } + }); +}); + +export function useTheme() { + return [ + theme, + (theme: Theme) => { + setTheme(theme); + localStorage.setItem("theme", theme); + }, + ] as const; +} diff --git a/apps/playground/src/index.css b/apps/playground/src/index.css new file mode 100644 index 00000000..8a143165 --- /dev/null +++ b/apps/playground/src/index.css @@ -0,0 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, body, #root { + height: 100%; +} diff --git a/apps/playground/src/index.tsx b/apps/playground/src/index.tsx new file mode 100644 index 00000000..f330751c --- /dev/null +++ b/apps/playground/src/index.tsx @@ -0,0 +1,9 @@ +/* @refresh reload */ +import { render } from "solid-js/web"; + +import App from "./App"; +import "./index.css"; + +const root = document.getElementById("root"); + +render(() => , root!); diff --git a/apps/playground/src/monaco/eval-selection.ts b/apps/playground/src/monaco/eval-selection.ts new file mode 100644 index 00000000..0332f75c --- /dev/null +++ b/apps/playground/src/monaco/eval-selection.ts @@ -0,0 +1,120 @@ +import generate from "@babel/generator"; +import * as t from "@babel/types"; +import * as monaco from "monaco-editor"; +import { evalCode } from "../sandbox"; + +export function registerEvalSelection( + editor: monaco.editor.IStandaloneCodeEditor, +): monaco.IDisposable { + const codeAction = monaco.languages.registerCodeActionProvider("javascript", { + provideCodeActions(_model, range) { + if (range.isEmpty()) return; + return { + actions: [ + { + title: "Evaluate and replace (value)", + kind: "refactor", + command: { + id: "editor.action.evaluate-expression", + title: "Evaluate and replace (value)", + }, + }, + { + title: "Evaluate and replace (raw)", + kind: "refactor", + command: { + id: "editor.action.evaluate-raw", + title: "Evaluate and replace (raw)", + }, + }, + ], + dispose: () => {}, + }; + }, + }); + + const evalValuesCommand = monaco.editor.registerCommand( + "editor.action.evaluate-expression", + // eslint-disable-next-line @typescript-eslint/no-misused-promises + evalValues, + ); + const evalRawCommand = monaco.editor.registerCommand( + "editor.action.evaluate-raw", + // eslint-disable-next-line @typescript-eslint/no-misused-promises + evalRaw, + ); + + const evalValueAction = editor.addAction({ + id: "editor.action.evaluate-expression", + label: "Evaluate and replace selection (value)", + precondition: "editorHasSelection", + keybindings: [monaco.KeyMod.Shift | monaco.KeyCode.Enter], + run: evalValues, + }); + + const evalRawAction = editor.addAction({ + id: "editor.action.evaluate-raw", + label: "Evaluate and replace selection (raw)", + precondition: "editorHasSelection", + keybindings: [ + monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Enter, + ], + run: evalRaw, + }); + + async function evalValues() { + const selections = editor.getSelections(); + if (!selections) return; + await evalSelections( + selections, + (value) => generate(t.valueToNode(value)).code, + ); + } + + async function evalRaw() { + const selections = editor.getSelections(); + if (!selections) return; + await evalSelections(selections, (value) => { + if (typeof value !== "string") { + console.error(value); + throw new Error("Evaluated value must be a string"); + } + return value; + }); + } + + async function evalSelections( + ranges: monaco.Range[], + mapper: (value: unknown) => string, + ) { + if (ranges.some((range) => range.isEmpty())) return; + + const expressions = ranges + .map((range) => { + const value = editor.getModel()!.getValueInRange(range); + return `eval(${JSON.stringify(value)})`; + }) + .join(","); + // New lines are added so line comments don't mess up the rest of the code + const code = `[\n${expressions}\n]`; + const values = (await evalCode(code)) as unknown[]; + + const edits = ranges.map((range, index) => ({ + range, + text: mapper(values[index]), + })); + + editor.pushUndoStop(); + editor.executeEdits("evaluate-expression", edits); + } + + return { + dispose() { + codeAction.dispose(); + evalValuesCommand.dispose(); + evalValueAction.dispose(); + evalRawCommand.dispose(); + evalRawAction.dispose(); + }, + }; +} diff --git a/apps/playground/src/monaco/placeholder-widget.ts b/apps/playground/src/monaco/placeholder-widget.ts new file mode 100644 index 00000000..c9279ed4 --- /dev/null +++ b/apps/playground/src/monaco/placeholder-widget.ts @@ -0,0 +1,49 @@ +import * as monaco from "monaco-editor"; + +// Based on https://github.com/microsoft/monaco-editor/issues/568#issuecomment-1499966160 +export class PlaceholderContentWidget implements monaco.editor.IContentWidget { + private domNode: HTMLElement; + + constructor( + private readonly placeholder: string, + private readonly editor: monaco.editor.ICodeEditor, + ) { + this.domNode = document.createElement("div"); + this.domNode.className = "placeholder"; + this.domNode.textContent = this.placeholder; + this.domNode.style.width = "max-content"; + this.domNode.style.fontStyle = "italic"; + this.domNode.style.pointerEvents = "none"; + this.editor.applyFontInfo(this.domNode); + + editor.onDidChangeModel(() => this.onDidChangeModelContent()); + editor.onDidChangeModelContent(() => this.onDidChangeModelContent()); + this.editor.addContentWidget(this); + } + + private onDidChangeModelContent() { + const shown = + this.editor.getValue() === "" && + this.editor.getModel()?.uri.scheme === "untitled"; + this.domNode.style.display = shown ? "block" : "none"; + } + + getId() { + return "editor.widget.placeholderHint"; + } + + getDomNode() { + return this.domNode; + } + + getPosition() { + return { + position: { lineNumber: 1, column: 1 }, + preference: [monaco.editor.ContentWidgetPositionPreference.EXACT], + }; + } + + dispose() { + this.editor.removeContentWidget(this); + } +} diff --git a/apps/playground/src/sandbox.ts b/apps/playground/src/sandbox.ts new file mode 100644 index 00000000..c81ba9bf --- /dev/null +++ b/apps/playground/src/sandbox.ts @@ -0,0 +1,12 @@ +import Sandybox from "sandybox"; + +const sandbox = await Sandybox.create(); +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +export async function evalCode(code: string) { + const fn = await sandbox.addFunction(`() => ${code}`); + return Promise.race([ + fn(), + sleep(10_000).then(() => Promise.reject("Sandbox timeout")), + ]).finally(() => sandbox.removeFunction(fn)); +} diff --git a/apps/playground/src/vite-env.d.ts b/apps/playground/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/apps/playground/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/playground/src/webcrack.worker.ts b/apps/playground/src/webcrack.worker.ts new file mode 100644 index 00000000..358e6fb4 --- /dev/null +++ b/apps/playground/src/webcrack.worker.ts @@ -0,0 +1,57 @@ +import { Options, Sandbox, webcrack } from "webcrack"; + +export type WorkerRequest = + | { type: "deobfuscate"; code: string; options: Options } + | { type: "sandbox"; result: unknown }; + +export type WorkerResponse = + | { type: "sandbox"; code: string } + | ({ type: "result" } & DeobfuscateResult) + | { type: "progress"; value: number } + | { type: "error"; error: unknown }; + +export interface DeobfuscateResult { + code: string; + files: { code: string; path: string }[]; +} + +const postMessage = (message: WorkerResponse) => self.postMessage(message); + +self.onmessage = async ({ data }: MessageEvent) => { + if (data.type !== "deobfuscate") return; + + // worker->window->sandybox because it accesses the DOM, which is not available in workers + const sandbox: Sandbox = (code) => { + return new Promise((resolve) => { + self.addEventListener("message", onSandboxResponse); + postMessage({ type: "sandbox", code }); + + function onSandboxResponse({ data }: MessageEvent) { + if (data.type === "sandbox") { + self.removeEventListener("message", onSandboxResponse); + resolve(data.result); + } + } + }); + }; + + function onProgress(value: number) { + postMessage({ type: "progress", value }); + } + + try { + const result = await webcrack(data.code, { + sandbox, + onProgress, + ...data.options, + }); + const files = Array.from(result.bundle?.modules ?? [], ([, module]) => ({ + code: module.code, + path: module.path.replace(/\.?\/?/, ""), + })); + + postMessage({ type: "result", code: result.code, files }); + } catch (error) { + postMessage({ type: "error", error }); + } +}; diff --git a/apps/playground/tailwind.config.ts b/apps/playground/tailwind.config.ts new file mode 100644 index 00000000..2579e23a --- /dev/null +++ b/apps/playground/tailwind.config.ts @@ -0,0 +1,36 @@ +import daisyui from "daisyui"; +import themes from "daisyui/src/theming/themes"; +import type { Config } from "tailwindcss"; + +const config: Config = { + content: ["./src/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: {}, + }, + daisyui: { + logs: false, + themes: [ + { + light: { + ...themes["light"], + "primary-content": "#edf2f7", + primary: "#409eea", + secondary: "#6366f1", + accent: "#34eca2", + }, + dark: { + ...themes["dark"], + "base-100": "#1b1b1f", + "base-200": "#161618", + "base-300": "#111113", + primary: "#409eea", + secondary: "#6366f1", + accent: "#34eca2", + }, + }, + ], + }, + plugins: [daisyui], +}; + +export default config; diff --git a/apps/playground/tsconfig.json b/apps/playground/tsconfig.json new file mode 100644 index 00000000..e3411e7e --- /dev/null +++ b/apps/playground/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@webcrack/typescript-config/vite.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js", + "paths": { + "webcrack": [ + "../../packages/webcrack/src" + ] + } + }, +} diff --git a/apps/playground/turbo.json b/apps/playground/turbo.json new file mode 100644 index 00000000..445dc532 --- /dev/null +++ b/apps/playground/turbo.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": [ + "//" + ], + "pipeline": { + "build": { + "dependsOn": [] + } + } +} diff --git a/apps/playground/vite.config.ts b/apps/playground/vite.config.ts new file mode 100644 index 00000000..7ca7383d --- /dev/null +++ b/apps/playground/vite.config.ts @@ -0,0 +1,49 @@ +import { defineConfig } from "vite"; +import monacoEditor from "vite-plugin-monaco-editor"; +import { nodePolyfills } from "vite-plugin-node-polyfills"; +import solid from "vite-plugin-solid"; + +const __dirname = new URL(".", import.meta.url).pathname; + +// https://github.com/vdesjs/vite-plugin-monaco-editor/issues/21 +const { default: monacoEditorPlugin } = monacoEditor as unknown as { + default: typeof monacoEditor; +}; + +export default defineConfig({ + optimizeDeps: { + exclude: ["isolated-vm"], + }, + build: { + target: "chrome89", + sourcemap: true, + rollupOptions: { + external: ["isolated-vm"], + output: { + format: "es", + manualChunks: (id) => { + if (id.includes("monaco-editor")) return "monaco-editor"; + }, + }, + }, + }, + worker: { + format: "es", + }, + resolve: { + alias: { + // @codemod/matchers imports @codemod/utils which imports @babel/core, but it's not needed + // by replacing it with a dummy module we can reduce the bundle size by 360kb + "@babel/core": __dirname + "/src/_empty.ts", + "isolated-vm": __dirname + "/src/_empty.ts", + webcrack: __dirname + "../../packages/webcrack/src", + }, + }, + plugins: [ + nodePolyfills({ exclude: ["fs"] }), + monacoEditorPlugin({ + languageWorkers: ["editorWorkerService", "typescript"], + }), + solid(), + ], +}); diff --git a/apps/web/netlify.toml b/apps/web/netlify.toml new file mode 100644 index 00000000..678b5e39 --- /dev/null +++ b/apps/web/netlify.toml @@ -0,0 +1,3 @@ +[build] +publish = "apps/web/dist" +command = "turbo run build --filter web" diff --git a/apps/web/package.json b/apps/web/package.json new file mode 100644 index 00000000..fce22181 --- /dev/null +++ b/apps/web/package.json @@ -0,0 +1,13 @@ +{ + "name": "web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "rm -rf dist && cp -r ../playground/dist dist && cp -r ../docs/dist/docs dist" + }, + "dependencies": { + "docs": "workspace:*", + "playground": "workspace:*" + } +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 1e9425ea..00000000 --- a/package-lock.json +++ /dev/null @@ -1,7380 +0,0 @@ -{ - "name": "webcrack", - "version": "2.10.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "webcrack", - "version": "2.10.0", - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.22.10", - "@babel/helper-validator-identifier": "^7.22.5", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", - "@codemod/matchers": "^1.7.0", - "babel-plugin-minify-mangle-names": "^0.5.1", - "commander": "^11.0.0", - "debug": "^4.3.4", - "isolated-vm": "^4.6.0" - }, - "bin": { - "webcrack": "dist/cli.js" - }, - "devDependencies": { - "@types/babel__generator": "^7.6.4", - "@types/babel__helper-validator-identifier": "^7.15.0", - "@types/babel__template": "^7.4.1", - "@types/babel__traverse": "^7.20.1", - "@types/debug": "^4.1.8", - "@types/node": "^20.5.0", - "@typescript-eslint/eslint-plugin": "^6.3.0", - "@typescript-eslint/parser": "^6.3.0", - "@vitest/coverage-istanbul": "^0.34.1", - "esbuild": "^0.19.2", - "eslint": "^8.47.0", - "typescript": "^5.1.6", - "vitest": "^0.34.1" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", - "dependencies": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", - "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.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", - "dependencies": { - "@babel/types": "^7.22.10", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "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/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "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.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "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.21.2", - "@babel/types": "^7.21.2" - }, - "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-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", - "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@codemod/matchers": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@codemod/matchers/-/matchers-1.7.0.tgz", - "integrity": "sha512-edfMWz/eckYmtpXuW6JINnWa81eKJ555KX+nn7gUoxQFI5qFY59DIsvZmhACOUpcYAFpF2rT8I7tiLgmZ1zMYQ==", - "dependencies": { - "@babel/types": "^7.20.7", - "@codemod/utils": "^1.1.0" - } - }, - "node_modules/@codemod/parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@codemod/parser/-/parser-1.4.0.tgz", - "integrity": "sha512-Qi7PVgvA+RzM8Zzx0BnhH4CnWuwvD4A3/QJZGSJLELxJZwQVI3dT0o/7WLD9lLAkdz0n2Rep/REpfVdTNap/dg==", - "dependencies": { - "@babel/parser": "^7.20.15" - } - }, - "node_modules/@codemod/utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@codemod/utils/-/utils-1.1.0.tgz", - "integrity": "sha512-Zx6A4xDifEqL0s9ejh62/mQmDXje+E62zYHGiGfRHzVhzmA41pDFZW/m7Hl9+fmbODJxlg9ElMsjHdhasSm7TA==", - "dependencies": { - "@babel/core": "^7.20.12", - "@babel/types": "^7.20.7", - "@codemod/parser": "^1.4.0" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", - "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", - "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", - "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", - "integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", - "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", - "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", - "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", - "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", - "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", - "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", - "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", - "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", - "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", - "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", - "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz", - "integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", - "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", - "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", - "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", - "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", - "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", - "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/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/schemas": { - "version": "29.6.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", - "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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/@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/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "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__helper-validator-identifier": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@types/babel__helper-validator-identifier/-/babel__helper-validator-identifier-7.15.0.tgz", - "integrity": "sha512-r7lKr83wzIIWvA8A08Yj294wNGcI7ZCxdDY2EuP14oIY3q+fmdCMXxzMeVHXJ116pZ5MeLol14/3TKbMQDdFKg==", - "dev": true - }, - "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.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", - "dev": true - }, - "node_modules/@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", - "dev": true, - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", - "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.3.0.tgz", - "integrity": "sha512-IZYjYZ0ifGSLZbwMqIip/nOamFiWJ9AH+T/GYNZBWkVcyNQOFGtSMoWV7RvY4poYCMZ/4lHzNl796WOSNxmk8A==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.3.0", - "@typescript-eslint/type-utils": "6.3.0", - "@typescript-eslint/utils": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.3.0.tgz", - "integrity": "sha512-ibP+y2Gr6p0qsUkhs7InMdXrwldjxZw66wpcQq9/PzAroM45wdwyu81T+7RibNCh8oc0AgrsyCwJByncY0Ongg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.3.0", - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/typescript-estree": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.3.0.tgz", - "integrity": "sha512-WlNFgBEuGu74ahrXzgefiz/QlVb+qg8KDTpknKwR7hMH+lQygWyx0CQFoUmMn1zDkQjTBBIn75IxtWss77iBIQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.3.0.tgz", - "integrity": "sha512-7Oj+1ox1T2Yc8PKpBvOKWhoI/4rWFd1j7FA/rPE0lbBPXTKjdbtC+7Ev0SeBjEKkIhKWVeZSP+mR7y1Db1CdfQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "6.3.0", - "@typescript-eslint/utils": "6.3.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.3.0.tgz", - "integrity": "sha512-K6TZOvfVyc7MO9j60MkRNWyFSf86IbOatTKGrpTQnzarDZPYPVy0oe3myTMq7VjhfsUAbNUW8I5s+2lZvtx1gg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.3.0.tgz", - "integrity": "sha512-Xh4NVDaC4eYKY4O3QGPuQNp5NxBAlEvNQYOqJquR2MePNxO11E5K3t5x4M4Mx53IZvtpW+mBxIT0s274fLUocg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.3.0.tgz", - "integrity": "sha512-hLLg3BZE07XHnpzglNBG8P/IXq/ZVXraEbgY7FM0Cnc1ehM8RMdn9mat3LubJ3KBeYXXPxV1nugWbQPjGeJk6Q==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.3.0", - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/typescript-estree": "6.3.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.3.0.tgz", - "integrity": "sha512-kEhRRj7HnvaSjux1J9+7dBen15CdWmDnwrpyiHsFX6Qx2iW5LOBUgNefOFeh2PjWPlNwN8TOn6+4eBU3J/gupw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.3.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitest/coverage-istanbul": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-0.34.1.tgz", - "integrity": "sha512-5GprlyY2t1g6+RrssWcN/w5RnZV3qIOM0eoaSDJw3jXbHpBpMvAfTg791zXo7PIqNYs5ORUqBWXIIU0gyAfZxA==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.1.5", - "test-exclude": "^6.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": ">=0.32.0 <1" - } - }, - "node_modules/@vitest/expect": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.1.tgz", - "integrity": "sha512-q2CD8+XIsQ+tHwypnoCk8Mnv5e6afLFvinVGCq3/BOT4kQdVQmY6rRfyKkwcg635lbliLPqbunXZr+L1ssUWiQ==", - "dev": true, - "dependencies": { - "@vitest/spy": "0.34.1", - "@vitest/utils": "0.34.1", - "chai": "^4.3.7" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/expect/node_modules/@vitest/utils": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.1.tgz", - "integrity": "sha512-/ql9dsFi4iuEbiNcjNHQWXBum7aL8pyhxvfnD9gNtbjR9fUKAjxhj4AA3yfLXg6gJpMGGecvtF8Au2G9y3q47Q==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/expect/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/@vitest/expect/node_modules/pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@vitest/expect/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/@vitest/runner": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.1.tgz", - "integrity": "sha512-YfQMpYzDsYB7yqgmlxZ06NI4LurHWfrH7Wy3Pvf/z/vwUSgq1zLAb1lWcItCzQG+NVox+VvzlKQrYEXb47645g==", - "dev": true, - "dependencies": { - "@vitest/utils": "0.34.1", - "p-limit": "^4.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/node_modules/@vitest/utils": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.1.tgz", - "integrity": "sha512-/ql9dsFi4iuEbiNcjNHQWXBum7aL8pyhxvfnD9gNtbjR9fUKAjxhj4AA3yfLXg6gJpMGGecvtF8Au2G9y3q47Q==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/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/@vitest/runner/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/runner/node_modules/pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@vitest/runner/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/@vitest/runner/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/snapshot": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.1.tgz", - "integrity": "sha512-0O9LfLU0114OqdF8lENlrLsnn024Tb1CsS9UwG0YMWY2oGTQfPtkW+B/7ieyv0X9R2Oijhi3caB1xgGgEgclSQ==", - "dev": true, - "dependencies": { - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "pretty-format": "^29.5.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot/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/@vitest/snapshot/node_modules/pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@vitest/snapshot/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/@vitest/spy": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.1.tgz", - "integrity": "sha512-UT4WcI3EAPUNO8n6y9QoEqynGGEPmmRxC+cLzneFFXpmacivjHZsNbiKD88KUScv5DCHVDgdBsLD7O7s1enFcQ==", - "dev": true, - "dependencies": { - "tinyspy": "^2.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/ui": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.32.2.tgz", - "integrity": "sha512-N5JKftnB8qzKFtpQC5OcUGxYTLo6wiB/95Lgyk6MF52t74Y7BJOWbf6EFYhXqt9J0MSbhOR2kapq+WKKUGDW0g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@vitest/utils": "0.32.2", - "fast-glob": "^3.2.12", - "fflate": "^0.7.4", - "flatted": "^3.2.7", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "sirv": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": ">=0.30.1 <1" - } - }, - "node_modules/@vitest/utils": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", - "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^27.5.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/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/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-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/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA==" - }, - "node_modules/babel-plugin-minify-mangle-names": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.1.tgz", - "integrity": "sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw==", - "dependencies": { - "babel-helper-mark-eval-scopes": "^0.4.3" - } - }, - "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/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "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/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.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/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/caniuse-lite": { - "version": "1.0.30001472", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001472.tgz", - "integrity": "sha512-xWC/0+hHHQgj3/vrKYY0AAzeIUgr7L9wlELIcAvZdDUHlhL/kNxMdnQLOSOQfP8R51ZzPhmHdyMkI0MMpmxCfg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "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/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", - "engines": { - "node": ">=16" - } - }, - "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/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/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.343", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.343.tgz", - "integrity": "sha512-22C6pOljO+QQ/yeBZJkxewjsGwSKCXymng7dF8lir3m8iJGi6guoLVkK8jghCf3o0/tARFASAgLP8OzR9SKRCA==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/esbuild": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.2.tgz", - "integrity": "sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.19.2", - "@esbuild/android-arm64": "0.19.2", - "@esbuild/android-x64": "0.19.2", - "@esbuild/darwin-arm64": "0.19.2", - "@esbuild/darwin-x64": "0.19.2", - "@esbuild/freebsd-arm64": "0.19.2", - "@esbuild/freebsd-x64": "0.19.2", - "@esbuild/linux-arm": "0.19.2", - "@esbuild/linux-arm64": "0.19.2", - "@esbuild/linux-ia32": "0.19.2", - "@esbuild/linux-loong64": "0.19.2", - "@esbuild/linux-mips64el": "0.19.2", - "@esbuild/linux-ppc64": "0.19.2", - "@esbuild/linux-riscv64": "0.19.2", - "@esbuild/linux-s390x": "0.19.2", - "@esbuild/linux-x64": "0.19.2", - "@esbuild/netbsd-x64": "0.19.2", - "@esbuild/openbsd-x64": "0.19.2", - "@esbuild/sunos-x64": "0.19.2", - "@esbuild/win32-arm64": "0.19.2", - "@esbuild/win32-ia32": "0.19.2", - "@esbuild/win32-x64": "0.19.2" - } - }, - "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/eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/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/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/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/eslint/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/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fflate": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", - "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "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/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-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-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/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "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/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isolated-vm": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-4.6.0.tgz", - "integrity": "sha512-MEnfC/54q5PED3VJ9UJYJPOlU6mYFHS3ivR9E8yeNNBEFRFUNBnY0xO4Rj3D/SOtFKPNmsQp9NWUYSKZqAoZiA==", - "hasInstallScript": true, - "dependencies": { - "prebuild-install": "^7.1.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", - "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", - "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": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-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/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": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.0" - } - }, - "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/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/magic-string/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "node_modules/mlly": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz", - "integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "pathe": "^1.1.1", - "pkg-types": "^1.0.3", - "ufo": "^1.1.2" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "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/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/node-abi": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", - "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" - }, - "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==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", - "dev": true, - "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" - } - }, - "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.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, - "optional": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.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/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/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/semver/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/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/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "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/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/sirv": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", - "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "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-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "node_modules/std-env": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", - "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==", - "dev": true - }, - "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/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-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/strip-literal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", - "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", - "dev": true, - "dependencies": { - "acorn": "^8.8.2" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "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/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tinybench": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", - "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", - "dev": true - }, - "node_modules/tinypool": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", - "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "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==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz", - "integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==", - "dev": true - }, - "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/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/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/vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", - "dev": true, - "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.1.tgz", - "integrity": "sha512-odAZAL9xFMuAg8aWd7nSPT+hU8u2r9gU3LRm9QKjxBEF2rRdWpMuqkrkjvyVQEdNFiBctqr2Gg4uJYizm5Le6w==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.4.0", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" - } - }, - "node_modules/vitest": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.1.tgz", - "integrity": "sha512-G1PzuBEq9A75XSU88yO5G4vPT20UovbC/2osB2KEuV/FisSIIsw7m5y2xMdB7RsAGHAfg2lPmp2qKr3KWliVlQ==", - "dev": true, - "dependencies": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.34.1", - "@vitest/runner": "0.34.1", - "@vitest/snapshot": "0.34.1", - "@vitest/spy": "0.34.1", - "@vitest/utils": "0.34.1", - "acorn": "^8.9.0", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.7", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.7.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.34.1", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", - "happy-dom": "*", - "jsdom": "*", - "playwright": "*", - "safaridriver": "*", - "webdriverio": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/@vitest/utils": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.1.tgz", - "integrity": "sha512-/ql9dsFi4iuEbiNcjNHQWXBum7aL8pyhxvfnD9gNtbjR9fUKAjxhj4AA3yfLXg6gJpMGGecvtF8Au2G9y3q47Q==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest/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/vitest/node_modules/pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/vitest/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/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/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "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==" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "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": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", - "requires": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==" - }, - "@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", - "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.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", - "requires": { - "@babel/types": "^7.22.10", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@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": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@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.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "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.21.2", - "@babel/types": "^7.21.2" - } - }, - "@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-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==" - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==" - }, - "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", - "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", - "requires": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - } - }, - "@codemod/matchers": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@codemod/matchers/-/matchers-1.7.0.tgz", - "integrity": "sha512-edfMWz/eckYmtpXuW6JINnWa81eKJ555KX+nn7gUoxQFI5qFY59DIsvZmhACOUpcYAFpF2rT8I7tiLgmZ1zMYQ==", - "requires": { - "@babel/types": "^7.20.7", - "@codemod/utils": "^1.1.0" - } - }, - "@codemod/parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@codemod/parser/-/parser-1.4.0.tgz", - "integrity": "sha512-Qi7PVgvA+RzM8Zzx0BnhH4CnWuwvD4A3/QJZGSJLELxJZwQVI3dT0o/7WLD9lLAkdz0n2Rep/REpfVdTNap/dg==", - "requires": { - "@babel/parser": "^7.20.15" - } - }, - "@codemod/utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@codemod/utils/-/utils-1.1.0.tgz", - "integrity": "sha512-Zx6A4xDifEqL0s9ejh62/mQmDXje+E62zYHGiGfRHzVhzmA41pDFZW/m7Hl9+fmbODJxlg9ElMsjHdhasSm7TA==", - "requires": { - "@babel/core": "^7.20.12", - "@babel/types": "^7.20.7", - "@codemod/parser": "^1.4.0" - } - }, - "@esbuild/android-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", - "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", - "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", - "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", - "integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", - "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", - "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", - "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", - "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", - "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", - "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", - "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", - "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", - "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", - "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", - "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz", - "integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", - "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", - "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", - "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", - "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", - "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", - "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - } - } - }, - "@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/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/schemas": { - "version": "29.6.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", - "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.27.8" - } - }, - "@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" - } - }, - "@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" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", - "dev": true, - "optional": true, - "peer": true - }, - "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "@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__helper-validator-identifier": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@types/babel__helper-validator-identifier/-/babel__helper-validator-identifier-7.15.0.tgz", - "integrity": "sha512-r7lKr83wzIIWvA8A08Yj294wNGcI7ZCxdDY2EuP14oIY3q+fmdCMXxzMeVHXJ116pZ5MeLol14/3TKbMQDdFKg==", - "dev": true - }, - "@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.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", - "dev": true, - "requires": { - "@babel/types": "^7.20.7" - } - }, - "@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", - "dev": true - }, - "@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", - "dev": true, - "requires": { - "@types/chai": "*" - } - }, - "@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dev": true, - "requires": { - "@types/ms": "*" - } - }, - "@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, - "@types/node": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", - "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==", - "dev": true - }, - "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.3.0.tgz", - "integrity": "sha512-IZYjYZ0ifGSLZbwMqIip/nOamFiWJ9AH+T/GYNZBWkVcyNQOFGtSMoWV7RvY4poYCMZ/4lHzNl796WOSNxmk8A==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.3.0", - "@typescript-eslint/type-utils": "6.3.0", - "@typescript-eslint/utils": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/parser": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.3.0.tgz", - "integrity": "sha512-ibP+y2Gr6p0qsUkhs7InMdXrwldjxZw66wpcQq9/PzAroM45wdwyu81T+7RibNCh8oc0AgrsyCwJByncY0Ongg==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "6.3.0", - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/typescript-estree": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.3.0.tgz", - "integrity": "sha512-WlNFgBEuGu74ahrXzgefiz/QlVb+qg8KDTpknKwR7hMH+lQygWyx0CQFoUmMn1zDkQjTBBIn75IxtWss77iBIQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.3.0.tgz", - "integrity": "sha512-7Oj+1ox1T2Yc8PKpBvOKWhoI/4rWFd1j7FA/rPE0lbBPXTKjdbtC+7Ev0SeBjEKkIhKWVeZSP+mR7y1Db1CdfQ==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "6.3.0", - "@typescript-eslint/utils": "6.3.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/types": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.3.0.tgz", - "integrity": "sha512-K6TZOvfVyc7MO9j60MkRNWyFSf86IbOatTKGrpTQnzarDZPYPVy0oe3myTMq7VjhfsUAbNUW8I5s+2lZvtx1gg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.3.0.tgz", - "integrity": "sha512-Xh4NVDaC4eYKY4O3QGPuQNp5NxBAlEvNQYOqJquR2MePNxO11E5K3t5x4M4Mx53IZvtpW+mBxIT0s274fLUocg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/visitor-keys": "6.3.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/utils": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.3.0.tgz", - "integrity": "sha512-hLLg3BZE07XHnpzglNBG8P/IXq/ZVXraEbgY7FM0Cnc1ehM8RMdn9mat3LubJ3KBeYXXPxV1nugWbQPjGeJk6Q==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.3.0", - "@typescript-eslint/types": "6.3.0", - "@typescript-eslint/typescript-estree": "6.3.0", - "semver": "^7.5.4" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.3.0.tgz", - "integrity": "sha512-kEhRRj7HnvaSjux1J9+7dBen15CdWmDnwrpyiHsFX6Qx2iW5LOBUgNefOFeh2PjWPlNwN8TOn6+4eBU3J/gupw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.3.0", - "eslint-visitor-keys": "^3.4.1" - } - }, - "@vitest/coverage-istanbul": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-0.34.1.tgz", - "integrity": "sha512-5GprlyY2t1g6+RrssWcN/w5RnZV3qIOM0eoaSDJw3jXbHpBpMvAfTg791zXo7PIqNYs5ORUqBWXIIU0gyAfZxA==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.1.5", - "test-exclude": "^6.0.0" - } - }, - "@vitest/expect": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.1.tgz", - "integrity": "sha512-q2CD8+XIsQ+tHwypnoCk8Mnv5e6afLFvinVGCq3/BOT4kQdVQmY6rRfyKkwcg635lbliLPqbunXZr+L1ssUWiQ==", - "dev": true, - "requires": { - "@vitest/spy": "0.34.1", - "@vitest/utils": "0.34.1", - "chai": "^4.3.7" - }, - "dependencies": { - "@vitest/utils": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.1.tgz", - "integrity": "sha512-/ql9dsFi4iuEbiNcjNHQWXBum7aL8pyhxvfnD9gNtbjR9fUKAjxhj4AA3yfLXg6gJpMGGecvtF8Au2G9y3q47Q==", - "dev": true, - "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - } - }, - "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 - }, - "pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "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 - } - } - }, - "@vitest/runner": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.1.tgz", - "integrity": "sha512-YfQMpYzDsYB7yqgmlxZ06NI4LurHWfrH7Wy3Pvf/z/vwUSgq1zLAb1lWcItCzQG+NVox+VvzlKQrYEXb47645g==", - "dev": true, - "requires": { - "@vitest/utils": "0.34.1", - "p-limit": "^4.0.0", - "pathe": "^1.1.1" - }, - "dependencies": { - "@vitest/utils": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.1.tgz", - "integrity": "sha512-/ql9dsFi4iuEbiNcjNHQWXBum7aL8pyhxvfnD9gNtbjR9fUKAjxhj4AA3yfLXg6gJpMGGecvtF8Au2G9y3q47Q==", - "dev": true, - "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - } - }, - "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 - }, - "p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "requires": { - "yocto-queue": "^1.0.0" - } - }, - "pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "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 - }, - "yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true - } - } - }, - "@vitest/snapshot": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.1.tgz", - "integrity": "sha512-0O9LfLU0114OqdF8lENlrLsnn024Tb1CsS9UwG0YMWY2oGTQfPtkW+B/7ieyv0X9R2Oijhi3caB1xgGgEgclSQ==", - "dev": true, - "requires": { - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "pretty-format": "^29.5.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 - }, - "pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "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 - } - } - }, - "@vitest/spy": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.1.tgz", - "integrity": "sha512-UT4WcI3EAPUNO8n6y9QoEqynGGEPmmRxC+cLzneFFXpmacivjHZsNbiKD88KUScv5DCHVDgdBsLD7O7s1enFcQ==", - "dev": true, - "requires": { - "tinyspy": "^2.1.1" - } - }, - "@vitest/ui": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.32.2.tgz", - "integrity": "sha512-N5JKftnB8qzKFtpQC5OcUGxYTLo6wiB/95Lgyk6MF52t74Y7BJOWbf6EFYhXqt9J0MSbhOR2kapq+WKKUGDW0g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@vitest/utils": "0.32.2", - "fast-glob": "^3.2.12", - "fflate": "^0.7.4", - "flatted": "^3.2.7", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "sirv": "^2.0.3" - } - }, - "@vitest/utils": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", - "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^27.5.1" - } - }, - "acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "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 - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "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" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA==" - }, - "babel-plugin-minify-mangle-names": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.1.tgz", - "integrity": "sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw==", - "requires": { - "babel-helper-mark-eval-scopes": "^0.4.3" - } - }, - "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 - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "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==", - "dev": true, - "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" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "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 - }, - "caniuse-lite": { - "version": "1.0.30001472", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001472.tgz", - "integrity": "sha512-xWC/0+hHHQgj3/vrKYY0AAzeIUgr7L9wlELIcAvZdDUHlhL/kNxMdnQLOSOQfP8R51ZzPhmHdyMkI0MMpmxCfg==" - }, - "chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "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" - } - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "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==" - }, - "commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==" - }, - "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==" - }, - "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" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "requires": { - "mimic-response": "^3.1.0" - } - }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.4.343", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.343.tgz", - "integrity": "sha512-22C6pOljO+QQ/yeBZJkxewjsGwSKCXymng7dF8lir3m8iJGi6guoLVkK8jghCf3o0/tARFASAgLP8OzR9SKRCA==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "esbuild": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.2.tgz", - "integrity": "sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.19.2", - "@esbuild/android-arm64": "0.19.2", - "@esbuild/android-x64": "0.19.2", - "@esbuild/darwin-arm64": "0.19.2", - "@esbuild/darwin-x64": "0.19.2", - "@esbuild/freebsd-arm64": "0.19.2", - "@esbuild/freebsd-x64": "0.19.2", - "@esbuild/linux-arm": "0.19.2", - "@esbuild/linux-arm64": "0.19.2", - "@esbuild/linux-ia32": "0.19.2", - "@esbuild/linux-loong64": "0.19.2", - "@esbuild/linux-mips64el": "0.19.2", - "@esbuild/linux-ppc64": "0.19.2", - "@esbuild/linux-riscv64": "0.19.2", - "@esbuild/linux-s390x": "0.19.2", - "@esbuild/linux-x64": "0.19.2", - "@esbuild/netbsd-x64": "0.19.2", - "@esbuild/openbsd-x64": "0.19.2", - "@esbuild/sunos-x64": "0.19.2", - "@esbuild/win32-arm64": "0.19.2", - "@esbuild/win32-ia32": "0.19.2", - "@esbuild/win32-x64": "0.19.2" - } - }, - "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==" - }, - "eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "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 - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "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" - } - } - } - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "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 - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fflate": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", - "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", - "dev": true, - "optional": true, - "peer": true - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "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 - }, - "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-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "dev": true - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "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" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "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 - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.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==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isolated-vm": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-4.6.0.tgz", - "integrity": "sha512-MEnfC/54q5PED3VJ9UJYJPOlU6mYFHS3ivR9E8yeNNBEFRFUNBnY0xO4Rj3D/SOtFKPNmsQp9NWUYSKZqAoZiA==", - "requires": { - "prebuild-install": "^7.1.1" - } - }, - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", - "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", - "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": "^7.5.4" - } - }, - "istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.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" - } - }, - "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": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", - "dev": true, - "requires": { - "get-func-name": "^2.0.0" - } - }, - "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" - } - }, - "magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - } - } - }, - "make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "requires": { - "semver": "^7.5.3" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" - }, - "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" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "mlly": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz", - "integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "pathe": "^1.1.1", - "pkg-types": "^1.0.3", - "ufo": "^1.1.2" - } - }, - "mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "dev": true, - "optional": true, - "peer": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node-abi": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", - "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", - "requires": { - "semver": "^7.3.5" - } - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "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": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "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-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", - "dev": true - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "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==", - "dev": true - }, - "pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", - "dev": true, - "requires": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" - } - }, - "postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", - "dev": true, - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "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, - "optional": true, - "peer": true - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - } - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "optional": true, - "peer": true - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "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" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "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 - }, - "siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sirv": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", - "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - } - }, - "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-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "std-env": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", - "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==", - "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" - } - }, - "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-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 - }, - "strip-literal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", - "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", - "dev": true, - "requires": { - "acorn": "^8.8.2" - } - }, - "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" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tinybench": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", - "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", - "dev": true - }, - "tinypool": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", - "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", - "dev": true - }, - "tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", - "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==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "optional": true, - "peer": true - }, - "ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", - "dev": true, - "requires": {} - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true - }, - "ufo": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz", - "integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==", - "dev": true - }, - "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" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", - "dev": true, - "requires": { - "esbuild": "^0.18.10", - "fsevents": "~2.3.2", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, - "dependencies": { - "@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "dev": true, - "optional": true - }, - "esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" - } - } - } - }, - "vite-node": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.1.tgz", - "integrity": "sha512-odAZAL9xFMuAg8aWd7nSPT+hU8u2r9gU3LRm9QKjxBEF2rRdWpMuqkrkjvyVQEdNFiBctqr2Gg4uJYizm5Le6w==", - "dev": true, - "requires": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.4.0", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" - } - }, - "vitest": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.1.tgz", - "integrity": "sha512-G1PzuBEq9A75XSU88yO5G4vPT20UovbC/2osB2KEuV/FisSIIsw7m5y2xMdB7RsAGHAfg2lPmp2qKr3KWliVlQ==", - "dev": true, - "requires": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.34.1", - "@vitest/runner": "0.34.1", - "@vitest/snapshot": "0.34.1", - "@vitest/spy": "0.34.1", - "@vitest/utils": "0.34.1", - "acorn": "^8.9.0", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.7", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.7.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.34.1", - "why-is-node-running": "^2.2.2" - }, - "dependencies": { - "@vitest/utils": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.1.tgz", - "integrity": "sha512-/ql9dsFi4iuEbiNcjNHQWXBum7aL8pyhxvfnD9gNtbjR9fUKAjxhj4AA3yfLXg6gJpMGGecvtF8Au2G9y3q47Q==", - "dev": true, - "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - } - }, - "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 - }, - "pretty-format": { - "version": "29.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", - "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - } - }, - "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 - } - } - }, - "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" - } - }, - "why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", - "dev": true, - "requires": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "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 index e62d8742..d1d8a798 100644 --- a/package.json +++ b/package.json @@ -1,71 +1,25 @@ { - "name": "webcrack", - "version": "2.10.0", - "description": "Deobfuscate, unminify and unpack bundled javascript", - "author": "j4k0xb", - "license": "MIT", - "type": "module", - "main": "dist/index.js", - "browser": "dist/browser.js", - "bin": "dist/cli.js", - "types": "dist/index.d.ts", - "files": [ - "dist" - ], + "private": true, "scripts": { - "build": "node esbuild.config.js", - "postbuild": "tsc -p tsconfig.build.json", - "watch": "node esbuild.config.js --watch", - "start": "node dist/cli.js", - "dev": "node esbuild.config.js && node --enable-source-maps dist/cli.js tmp/test.js -f -o tmp/webcrack-out", - "lint": "eslint --ext .ts .", + "build": "turbo run build", + "dev": "turbo run dev --parallel", + "lint": "turbo run lint", + "lint:fix": "turbo run lint:fix", "test": "vitest", - "coverage": "vitest run --coverage" - }, - "repository": { - "type": "git", - "url": "https://github.com/j4k0xb/webcrack" - }, - "homepage": "https://webcrack.netlify.app", - "keywords": [ - "webpack", - "bundle", - "extract", - "reverse-engineering", - "ast", - "deobfuscation", - "unpack", - "debundle", - "deobfuscator", - "unminify", - "unbundle" - ], - "dependencies": { - "@babel/generator": "^7.22.10", - "@babel/helper-validator-identifier": "^7.22.5", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", - "@codemod/matchers": "^1.7.0", - "babel-plugin-minify-mangle-names": "^0.5.1", - "commander": "^11.0.0", - "debug": "^4.3.4", - "isolated-vm": "^4.6.0" + "test:coverage": "vitest --coverage", + "format": "prettier --write \"**/*.{ts,tsx,md}\"" }, "devDependencies": { - "@types/babel__generator": "^7.6.4", - "@types/babel__helper-validator-identifier": "^7.15.0", - "@types/babel__template": "^7.4.1", - "@types/babel__traverse": "^7.20.1", - "@types/debug": "^4.1.8", - "@types/node": "^20.5.0", - "@typescript-eslint/eslint-plugin": "^6.3.0", - "@typescript-eslint/parser": "^6.3.0", - "@vitest/coverage-istanbul": "^0.34.1", - "esbuild": "^0.19.2", - "eslint": "^8.47.0", - "typescript": "^5.1.6", - "vitest": "^0.34.1" + "@webcrack/eslint-config": "workspace:*", + "eslint": "^8.54.0", + "prettier": "^3.1.0", + "turbo": "^1.10.16", + "vitest": "^0.34.6" + }, + "packageManager": "pnpm@8.11.0", + "pnpm": { + "patchedDependencies": { + "vite-plugin-monaco-editor@1.1.0": "patches/vite-plugin-monaco-editor@1.1.0.patch" + } } } diff --git a/packages/ast-utils/.eslintrc.cjs b/packages/ast-utils/.eslintrc.cjs new file mode 100644 index 00000000..d0f2c30e --- /dev/null +++ b/packages/ast-utils/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], +}; diff --git a/packages/ast-utils/package.json b/packages/ast-utils/package.json new file mode 100644 index 00000000..2c5f84f3 --- /dev/null +++ b/packages/ast-utils/package.json @@ -0,0 +1,29 @@ +{ + "name": "@webcrack/ast-utils", + "version": "1.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "lint": "eslint src test", + "lint:fix": "eslint src test --fix", + "test": "vitest" + }, + "dependencies": { + "@babel/generator": "^7.23.5", + "@babel/helper-validator-identifier": "^7.22.20", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "@codemod/matchers": "^1.7.0" + }, + "devDependencies": { + "@types/babel__generator": "^7.6.7", + "@types/babel__helper-validator-identifier": "^7.15.2", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.20.4", + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "typescript": "^5.3.2" + } +} diff --git a/packages/ast-utils/src/ast.ts b/packages/ast-utils/src/ast.ts new file mode 100644 index 00000000..40385929 --- /dev/null +++ b/packages/ast-utils/src/ast.ts @@ -0,0 +1,13 @@ +import * as t from "@babel/types"; + +export function getPropName(node: t.Node): string | undefined { + if (t.isIdentifier(node)) { + return node.name; + } + if (t.isStringLiteral(node)) { + return node.value; + } + if (t.isNumericLiteral(node)) { + return node.value.toString(); + } +} diff --git a/packages/ast-utils/src/generator.ts b/packages/ast-utils/src/generator.ts new file mode 100644 index 00000000..e978a7e0 --- /dev/null +++ b/packages/ast-utils/src/generator.ts @@ -0,0 +1,23 @@ +import babelGenerate, { GeneratorOptions } from "@babel/generator"; +import * as t from "@babel/types"; + +const defaultOptions: GeneratorOptions = { jsescOption: { minimal: true } }; + +export function generate( + ast: t.Node, + options: GeneratorOptions = defaultOptions, +): string { + return babelGenerate(ast, options).code; +} + +export function codePreview(node: t.Node): string { + const code = generate(node, { + minified: true, + shouldPrintComment: () => false, + ...defaultOptions, + }); + if (code.length > 100) { + return code.slice(0, 70) + " … " + code.slice(-30); + } + return code; +} diff --git a/packages/ast-utils/src/index.ts b/packages/ast-utils/src/index.ts new file mode 100644 index 00000000..d1ed061d --- /dev/null +++ b/packages/ast-utils/src/index.ts @@ -0,0 +1,6 @@ +export * from "./ast"; +export * from "./generator"; +export * from "./inline"; +export * from "./matcher"; +export * from "./rename"; +export * from "./transform"; diff --git a/src/utils/inline.ts b/packages/ast-utils/src/inline.ts similarity index 83% rename from src/utils/inline.ts rename to packages/ast-utils/src/inline.ts index d5d6aad9..0b29c5ae 100644 --- a/src/utils/inline.ts +++ b/packages/ast-utils/src/inline.ts @@ -1,7 +1,7 @@ -import traverse, { Binding, NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { findParent } from './matcher'; +import traverse, { Binding, NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { findParent } from "./matcher"; /** * Make sure the array is immutable and references are valid before using! @@ -11,7 +11,7 @@ import { findParent } from './matcher'; */ export function inlineArrayElements( array: t.ArrayExpression, - references: NodePath[] + references: NodePath[], ): void { for (const reference of references) { const memberPath = reference.parentPath! as NodePath; @@ -32,14 +32,14 @@ export function inlineArrayElements( */ export function inlineCfFunction( fn: t.FunctionExpression, - caller: NodePath + caller: NodePath, ): void { if (t.isRestElement(fn.params[1])) { caller.replaceWith( t.callExpression( caller.node.arguments[0] as t.Identifier, - caller.node.arguments.slice(1) - ) + caller.node.arguments.slice(1), + ), ); return; } @@ -51,7 +51,7 @@ export function inlineCfFunction( traverse(clone, { Identifier(path) { const paramIndex = fn.params.findIndex( - p => (p as t.Identifier).name === path.node.name + (p) => (p as t.Identifier).name === path.node.name, ); if (paramIndex !== -1) { path.replaceWith(caller.node.arguments[paramIndex]); @@ -83,22 +83,22 @@ export function inlineFunctionAliases(binding: Binding): { changes: number } { const returnedCall = m.capture( m.callExpression( m.identifier(binding.identifier.name), - m.anyList(m.slice({ min: 2 })) - ) + m.anyList(m.slice({ min: 2 })), + ), ); const matcher = m.functionDeclaration( m.identifier(fnName), m.anyList(m.slice({ min: 2 })), - m.blockStatement([m.returnStatement(returnedCall)]) + m.blockStatement([m.returnStatement(returnedCall)]), ); if (fn && matcher.match(fn.node)) { // Avoid false positives of functions that return a string // It's only a wrapper if the function's params are used in the decode call - const paramUsedInDecodeCall = fn.node.params.some(param => { + const paramUsedInDecodeCall = fn.node.params.some((param) => { const binding = fn.scope.getBinding((param as t.Identifier).name); - return binding?.referencePaths.some(ref => - ref.findParent(p => p.node === returnedCall.current) + return binding?.referencePaths.some((ref) => + ref.findParent((p) => p.node === returnedCall.current), ); }); if (!paramUsedInDecodeCall) continue; @@ -112,11 +112,11 @@ export function inlineFunctionAliases(binding: Binding): { changes: number } { // E.g. [alias(1071, 1077), alias(1, 2)] const callRefs = fnRefs .filter( - ref => + (ref) => t.isCallExpression(ref.parent) && - t.isIdentifier(ref.parent.callee, { name: fnName.current! }) + t.isIdentifier(ref.parent.callee, { name: fnName.current! }), ) - .map(ref => ref.parentPath!) as NodePath[]; + .map((ref) => ref.parentPath!) as NodePath[]; for (const callRef of callRefs) { const fnClone = t.cloneNode(fn.node, true); @@ -125,7 +125,7 @@ export function inlineFunctionAliases(binding: Binding): { changes: number } { traverse(fnClone.body, { Identifier(path) { const paramIndex = fnClone.params.findIndex( - p => (p as t.Identifier).name === path.node.name + (p) => (p as t.Identifier).name === path.node.name, ); if (paramIndex !== -1) { path.replaceWith(callRef.node.arguments[paramIndex]); @@ -137,7 +137,7 @@ export function inlineFunctionAliases(binding: Binding): { changes: number } { // Replace the alias call itself with the return value callRef.replaceWith( - (fnClone.body.body[0] as t.ReturnStatement).argument! + (fnClone.body.body[0] as t.ReturnStatement).argument!, ); state.changes++; } @@ -161,7 +161,7 @@ export function inlineFunctionAliases(binding: Binding): { changes: number } { export function inlineVariableAliases( binding: Binding, - targetName = binding.identifier.name + targetName = binding.identifier.name, ): { changes: number } { const state = { changes: 0 }; const refs = [...binding.referencePaths]; @@ -169,13 +169,13 @@ export function inlineVariableAliases( const matcher = m.or( m.variableDeclarator( m.identifier(varName), - m.identifier(binding.identifier.name) + m.identifier(binding.identifier.name), ), m.assignmentExpression( - '=', + "=", m.identifier(varName), - m.identifier(binding.identifier.name) - ) + m.identifier(binding.identifier.name), + ), ); for (const ref of refs) { diff --git a/src/utils/matcher.ts b/packages/ast-utils/src/matcher.ts similarity index 73% rename from src/utils/matcher.ts rename to packages/ast-utils/src/matcher.ts index c2e5d128..60275559 100644 --- a/src/utils/matcher.ts +++ b/packages/ast-utils/src/matcher.ts @@ -1,38 +1,38 @@ -import { Binding, NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; +import { Binding, NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; export function infiniteLoop( - body?: m.Matcher + body?: m.Matcher, ): m.Matcher { return m.or( m.forStatement(undefined, null, undefined, body), m.forStatement(undefined, truthyMatcher, undefined, body), - m.whileStatement(truthyMatcher, body) + m.whileStatement(truthyMatcher, body), ); } export function constKey( - name?: string | m.Matcher + name?: string | m.Matcher, ): m.Matcher { return m.or(m.identifier(name), m.stringLiteral(name)); } export function constObjectProperty( - value?: m.Matcher + value?: m.Matcher, ): m.Matcher { return m.or( m.objectProperty(m.identifier(), value, false), - m.objectProperty(m.or(m.stringLiteral(), m.numericLiteral()), value) + m.objectProperty(m.or(m.stringLiteral(), m.numericLiteral()), value), ); } export function matchIife( - body?: m.Matcher | m.Matcher[] + body?: m.Matcher | m.Matcher[], ): m.Matcher { return m.callExpression( m.functionExpression(null, [], body ? m.blockStatement(body) : undefined), - [] + [], ); } @@ -44,25 +44,25 @@ export const emptyIife = matchIife([]); */ export function constMemberExpression( object: string | m.Matcher, - property?: string | m.Matcher + property?: string | m.Matcher, ): m.Matcher { - if (typeof object === 'string') object = m.identifier(object); + if (typeof object === "string") object = m.identifier(object); return m.or( m.memberExpression(object, m.identifier(property), false), - m.memberExpression(object, m.stringLiteral(property), true) + m.memberExpression(object, m.stringLiteral(property), true), ); } export const trueMatcher = m.or( m.booleanLiteral(true), - m.unaryExpression('!', m.numericLiteral(0)), - m.unaryExpression('!', m.unaryExpression('!', m.numericLiteral(1))), - m.unaryExpression('!', m.unaryExpression('!', m.arrayExpression([]))) + m.unaryExpression("!", m.numericLiteral(0)), + m.unaryExpression("!", m.unaryExpression("!", m.numericLiteral(1))), + m.unaryExpression("!", m.unaryExpression("!", m.arrayExpression([]))), ); export const falseMatcher = m.or( m.booleanLiteral(false), - m.unaryExpression('!', m.arrayExpression([])) + m.unaryExpression("!", m.arrayExpression([])), ); export const truthyMatcher = m.or(trueMatcher, m.arrayExpression([])); @@ -74,10 +74,10 @@ export const truthyMatcher = m.or(trueMatcher, m.arrayExpression([])); */ export function findParent( path: NodePath, - matcher: m.Matcher + matcher: m.Matcher, ): NodePath | null { - return path.findParent(path => - matcher.match(path.node) + return path.findParent((path) => + matcher.match(path.node), ) as NodePath | null; } @@ -88,9 +88,9 @@ export function findParent( */ export function findPath( path: NodePath, - matcher: m.Matcher + matcher: m.Matcher, ): NodePath | null { - return path.find(path => matcher.match(path.node)) as NodePath | null; + return path.find((path) => matcher.match(path.node)) as NodePath | null; } /** @@ -101,16 +101,18 @@ export function createFunctionMatcher( params: number, body: ( ...captures: m.Matcher[] - ) => m.Matcher | m.Matcher[] + ) => m.Matcher | m.Matcher[], ): m.Matcher { const captures = Array.from({ length: params }, () => - m.capture(m.anyString()) + m.capture(m.anyString()), ); return m.functionExpression( undefined, captures.map(m.identifier), - m.blockStatement(body(...captures.map(c => m.identifier(m.fromCapture(c))))) + m.blockStatement( + body(...captures.map((c) => m.identifier(m.fromCapture(c)))), + ), ); } @@ -119,7 +121,7 @@ export function createFunctionMatcher( */ export function isReadonlyObject( binding: Binding, - memberAccess: m.Matcher + memberAccess: m.Matcher, ): boolean { // Workaround because sometimes babel treats the VariableDeclarator/binding itself as a violation if (!binding.constant && binding.constantViolations[0] !== binding.path) @@ -139,7 +141,7 @@ export function isReadonlyObject( } return binding.referencePaths.every( - path => + (path) => // obj.property memberAccess.match(path.parent) && // obj.property = 1 @@ -153,8 +155,8 @@ export function isReadonlyObject( // delete obj.property !path.parentPath?.parentPath?.isUnaryExpression({ argument: path.parent, - operator: 'delete', + operator: "delete", }) && - !isPatternAssignment(path.parentPath!) + !isPatternAssignment(path.parentPath!), ); } diff --git a/src/matchers.d.ts b/packages/ast-utils/src/matchers.d.ts similarity index 81% rename from src/matchers.d.ts rename to packages/ast-utils/src/matchers.d.ts index 443dc9c5..01526964 100644 --- a/src/matchers.d.ts +++ b/packages/ast-utils/src/matchers.d.ts @@ -1,8 +1,8 @@ -import { Matcher } from '@codemod/matchers'; +import { Matcher } from "@codemod/matchers"; type MatcherType = T extends Matcher ? U : T; -declare module '@codemod/matchers' { +declare module "@codemod/matchers" { // The library only implements up to 5 arguments, but we need more // Also have to keep the other ones because of recursive matchers (numberExpressions.ts) @@ -10,32 +10,32 @@ declare module '@codemod/matchers' { export function or(first: Matcher | T): Matcher; export function or( first: Matcher | T, - second: Matcher | U + second: Matcher | U, ): Matcher; export function or( first: Matcher | T, second: Matcher | U, - third: Matcher | V + third: Matcher | V, ): Matcher; export function or( first: Matcher | T, second: Matcher | U, third: Matcher | V, - fourth: Matcher | W + fourth: Matcher | W, ): Matcher; export function or( first: Matcher | T, second: Matcher | U, third: Matcher | V, fourth: Matcher | W, - fifth: Matcher | X + fifth: Matcher | X, ): Matcher; export function or( ...matchers: T ): Matcher>; } -declare module '@codemod/matchers/build/matchers/predicate' { +declare module "@codemod/matchers/build/matchers/predicate" { // Convenience overload for not having to cast the value when using it export function predicate(predicate: (value: T) => boolean): Matcher; } diff --git a/src/utils/rename.ts b/packages/ast-utils/src/rename.ts similarity index 76% rename from src/utils/rename.ts rename to packages/ast-utils/src/rename.ts index 85555911..fd80946a 100644 --- a/src/utils/rename.ts +++ b/packages/ast-utils/src/rename.ts @@ -1,15 +1,16 @@ -import traverse, { Binding, NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import assert from 'assert'; -import { codePreview } from './ast'; +import traverse, { Binding, NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { codePreview } from "./generator"; export function renameFast(binding: Binding, newName: string): void { - binding.referencePaths.forEach(ref => { - assert( - ref.isIdentifier(), - `Unexpected reference (${ref.type}): ${codePreview(ref.node)}` - ); + binding.referencePaths.forEach((ref) => { + if (!ref.isIdentifier()) { + throw new Error( + `Unexpected reference (${ref.type}): ${codePreview(ref.node)}`, + ); + } + // To avoid conflicts with other bindings of the same name if (ref.scope.hasBinding(newName)) ref.scope.rename(newName); ref.node.name = newName; @@ -17,10 +18,10 @@ export function renameFast(binding: Binding, newName: string): void { // Also update assignments const patternMatcher = m.assignmentExpression( - '=', - m.or(m.arrayPattern(), m.objectPattern()) + "=", + m.or(m.arrayPattern(), m.objectPattern()), ); - binding.constantViolations.forEach(ref => { + binding.constantViolations.forEach((ref) => { // To avoid conflicts with other bindings of the same name if (ref.scope.hasBinding(newName)) ref.scope.rename(newName); @@ -42,7 +43,7 @@ export function renameFast(binding: Binding, newName: string): void { }); } else { throw new Error( - `Unexpected constant violation (${ref.type}): ${codePreview(ref.node)}` + `Unexpected constant violation (${ref.type}): ${codePreview(ref.node)}`, ); } }); @@ -54,7 +55,7 @@ export function renameFast(binding: Binding, newName: string): void { export function renameParameters( path: NodePath, - newNames: string[] + newNames: string[], ): void { const params = path.node.params as t.Identifier[]; for (let i = 0; i < Math.min(params.length, newNames.length); i++) { diff --git a/src/transforms/index.ts b/packages/ast-utils/src/transform.ts similarity index 57% rename from src/transforms/index.ts rename to packages/ast-utils/src/transform.ts index bf09b9a4..ae7dc780 100644 --- a/src/transforms/index.ts +++ b/packages/ast-utils/src/transform.ts @@ -1,40 +1,33 @@ -import traverse, { Node, TraverseOptions, visitors } from '@babel/traverse'; -import debug from 'debug'; - -const logger = debug('webcrack:transforms'); +import traverse, { Node, TraverseOptions, visitors } from "@babel/traverse"; export async function applyTransformAsync( ast: Node, transform: AsyncTransform, - options?: TOptions + options?: TOptions, ): Promise { - logger(`${transform.name}: started`); - const state: TransformState = { changes: 0 }; await transform.run?.(ast, state, options); if (transform.visitor) traverse(ast, transform.visitor(options), undefined, state); - logger(`${transform.name}: finished with ${state.changes} changes`); - return state; } export function applyTransform( ast: Node, transform: Transform, - options?: TOptions + options?: TOptions, ): TransformState { - logger(`${transform.name}: started`); - const state: TransformState = { changes: 0 }; transform.run?.(ast, state, options); - if (transform.visitor) - traverse(ast, transform.visitor(options), undefined, state); - logger(`${transform.name}: finished with ${state.changes} changes`); + if (transform.visitor) { + const visitor = transform.visitor(options); + visitor.noScope = !transform.scope; + traverse(ast, visitor, undefined, state); + } return state; } @@ -42,27 +35,21 @@ export function applyTransform( export function applyTransforms( ast: Node, transforms: Transform[], - name?: string ): TransformState { - name ??= transforms.map(t => t.name).join(', '); - logger(`${name}: started`); - const state: TransformState = { changes: 0 }; for (const transform of transforms) { transform.run?.(ast, state); } - const traverseOptions = transforms.flatMap(t => t.visitor?.() ?? []); + const traverseOptions = transforms.flatMap((t) => t.visitor?.() ?? []); if (traverseOptions.length > 0) { - const visitor = visitors.merge(traverseOptions); - // @ts-expect-error regression from https://github.com/babel/babel/pull/15702 - visitor.noScope = traverseOptions.every(t => t.noScope); + const visitor: TraverseOptions = + visitors.merge(traverseOptions); + visitor.noScope = transforms.every((t) => !t.scope); traverse(ast, visitor, undefined, state); } - logger(`${name}: finished with ${state.changes} changes`); - return state; } @@ -73,6 +60,7 @@ export interface TransformState { export interface Transform { name: string; tags: Tag[]; + scope?: boolean; run?: (ast: Node, state: TransformState, options?: TOptions) => void; visitor?: (options?: TOptions) => TraverseOptions; } @@ -82,4 +70,4 @@ export interface AsyncTransform run?: (ast: Node, state: TransformState, options?: TOptions) => Promise; } -export type Tag = 'safe' | 'unsafe'; +export type Tag = "safe" | "unsafe"; diff --git a/packages/ast-utils/test/rename.test.ts b/packages/ast-utils/test/rename.test.ts new file mode 100644 index 00000000..3b1d0d29 --- /dev/null +++ b/packages/ast-utils/test/rename.test.ts @@ -0,0 +1,81 @@ +import { parse } from "@babel/parser"; +import traverse from "@babel/traverse"; +import { describe, expect, test } from "vitest"; +import { renameFast, renameParameters } from "../src/rename"; + +describe("rename variable", () => { + test("conflict with existing binding", () => { + const ast = parse("let a = 1; let b = a;"); + traverse(ast, { + Program(path) { + const binding = path.scope.getBinding("a")!; + renameFast(binding, "b"); + + expect(path.scope.bindings).keys("b", "_b"); + }, + }); + expect(ast).toMatchInlineSnapshot(` + let b = 1; + let _b = b; + `); + }); + + test("different types of assignments", () => { + const ast = parse(` + var a = 1; + var a = 2; + a++; + [a] = [2]; + ({...a} = {}); + for (a of []); + for (a in []); + `); + traverse(ast, { + Program(path) { + const binding = path.scope.getBinding("a")!; + renameFast(binding, "b"); + }, + }); + expect(ast).toMatchInlineSnapshot(` + var b = 1; + var b = 2; + b++; + [b] = [2]; + ({ + ...b + } = {}); + for (b of []); + for (b in []); + `); + }); +}); + +describe("rename parameters", () => { + test("fewer than specified", () => { + const ast = parse("function f(a, b, c) { a + b + c;}"); + traverse(ast, { + Function(path) { + renameParameters(path, ["x", "y"]); + }, + }); + expect(ast).toMatchInlineSnapshot(` + function f(x, y, c) { + x + y + c; + } + `); + }); + + test("more than specified", () => { + const ast = parse("function f(a, b, c) { a + b + c;}"); + traverse(ast, { + Function(path) { + renameParameters(path, ["x", "y", "z", "w"]); + }, + }); + expect(ast).toMatchInlineSnapshot(` + function f(x, y, z) { + x + y + z; + } + `); + }); +}); diff --git a/packages/ast-utils/test/setup.ts b/packages/ast-utils/test/setup.ts new file mode 100644 index 00000000..d2615173 --- /dev/null +++ b/packages/ast-utils/test/setup.ts @@ -0,0 +1,8 @@ +import * as t from "@babel/types"; +import { expect } from "vitest"; +import { generate } from "../src/generator"; + +expect.addSnapshotSerializer({ + test: (val: unknown) => t.isNode(val) && !("parentPath" in val), + serialize: (val: t.Node) => generate(val), +}); diff --git a/packages/ast-utils/tsconfig.json b/packages/ast-utils/tsconfig.json new file mode 100644 index 00000000..fca8f92b --- /dev/null +++ b/packages/ast-utils/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@webcrack/typescript-config/base.json", +} diff --git a/packages/ast-utils/vitest.config.ts b/packages/ast-utils/vitest.config.ts new file mode 100644 index 00000000..cd893d71 --- /dev/null +++ b/packages/ast-utils/vitest.config.ts @@ -0,0 +1,11 @@ +import { join } from "node:path"; +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + root: join(__dirname, "test"), + setupFiles: "setup.ts", + include: ["**/*.test.ts"], + isolate: false, + }, +}); diff --git a/packages/config-eslint/index.js b/packages/config-eslint/index.js new file mode 100644 index 00000000..017f875c --- /dev/null +++ b/packages/config-eslint/index.js @@ -0,0 +1,18 @@ +/** + * @type {import("eslint").Linter.Config} + */ +module.exports = { + parser: "@typescript-eslint/parser", + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended-type-checked", + "prettier", + ], + ignorePatterns: [".eslintrc.cjs", "dist", "*.js", "*.snap"], + plugins: ["@typescript-eslint"], + parserOptions: { + sourceType: "module", + ecmaVersion: "latest", + project: true, + }, +}; diff --git a/packages/config-eslint/package.json b/packages/config-eslint/package.json new file mode 100644 index 00000000..4c5364f6 --- /dev/null +++ b/packages/config-eslint/package.json @@ -0,0 +1,11 @@ +{ + "name": "@webcrack/eslint-config", + "version": "0.0.0", + "main": "index.js", + "private": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^6.13.1", + "@typescript-eslint/parser": "^6.13.1", + "eslint-config-prettier": "^9.0.0" + } +} diff --git a/packages/config-typescript/base.json b/packages/config-typescript/base.json new file mode 100644 index 00000000..766703c0 --- /dev/null +++ b/packages/config-typescript/base.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Default", + "compilerOptions": { + "composite": false, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "exclude": [ + "node_modules" + ] +} diff --git a/packages/config-typescript/package.json b/packages/config-typescript/package.json new file mode 100644 index 00000000..9299ae23 --- /dev/null +++ b/packages/config-typescript/package.json @@ -0,0 +1,5 @@ +{ + "name": "@webcrack/typescript-config", + "version": "0.0.0", + "private": true +} diff --git a/packages/config-typescript/vite.json b/packages/config-typescript/vite.json new file mode 100644 index 00000000..4f655dfa --- /dev/null +++ b/packages/config-typescript/vite.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": [ + "ESNext", + "DOM" + ], + "sourceMap": true, + "resolveJsonModule": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true + }, + "exclude": [ + "node_modules" + ] +} diff --git a/packages/deobfuscate/.eslintrc.cjs b/packages/deobfuscate/.eslintrc.cjs new file mode 100644 index 00000000..d0f2c30e --- /dev/null +++ b/packages/deobfuscate/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], +}; diff --git a/packages/deobfuscate/package.json b/packages/deobfuscate/package.json new file mode 100644 index 00000000..907e2840 --- /dev/null +++ b/packages/deobfuscate/package.json @@ -0,0 +1,30 @@ +{ + "name": "@webcrack/deobfuscate", + "version": "1.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "lint": "eslint src test", + "lint:fix": "eslint src test --fix", + "test": "vitest" + }, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "@codemod/matchers": "^1.7.0", + "@webcrack/ast-utils": "workspace:*", + "isolated-vm": "^4.6.0" + }, + "devDependencies": { + "@types/babel__generator": "^7.6.7", + "@types/babel__helper-validator-identifier": "^7.15.2", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.20.4", + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "typescript": "^5.3.2" + } +} diff --git a/src/deobfuscator/arrayRotator.ts b/packages/deobfuscate/src/array-rotator.ts similarity index 66% rename from src/deobfuscator/arrayRotator.ts rename to packages/deobfuscate/src/array-rotator.ts index c8ff4fa3..f5cf525b 100644 --- a/src/deobfuscator/arrayRotator.ts +++ b/packages/deobfuscate/src/array-rotator.ts @@ -1,13 +1,13 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { callExpression } from '@codemod/matchers'; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { callExpression } from "@codemod/matchers"; import { constMemberExpression, findParent, infiniteLoop, -} from '../utils/matcher'; -import { StringArray } from './stringArray'; +} from "@webcrack/ast-utils"; +import { StringArray } from "./string-array"; export type ArrayRotator = NodePath; @@ -24,19 +24,19 @@ export type ArrayRotator = NodePath; * ``` */ export function findArrayRotator( - stringArray: StringArray + stringArray: StringArray, ): ArrayRotator | undefined { // e.g. 'array' const arrayIdentifier = m.capture(m.identifier()); // e.g. array.push(array.shift()) const pushShift = m.callExpression( - constMemberExpression(arrayIdentifier, 'push'), + constMemberExpression(arrayIdentifier, "push"), [ m.callExpression( - constMemberExpression(m.fromCapture(arrayIdentifier), 'shift') + constMemberExpression(m.fromCapture(arrayIdentifier), "shift"), ), - ] + ], ); const callMatcher = m.callExpression( @@ -47,29 +47,29 @@ export function findArrayRotator( m.anyList( m.zeroOrMore(), infiniteLoop( - m.matcher(node => { + m.matcher((node) => { return ( m - .containerOf(callExpression(m.identifier('parseInt'))) + .containerOf(callExpression(m.identifier("parseInt"))) .match(node) && m .blockStatement([ m.tryStatement( m.containerOf(pushShift), - m.containerOf(pushShift) + m.containerOf(pushShift), ), ]) .match(node) ); - }) - ) - ) - ) - ) + }), + ), + ), + ), + ), ); const matcher = m.expressionStatement( - m.or(callMatcher, m.unaryExpression('!', callMatcher)) + m.or(callMatcher, m.unaryExpression("!", callMatcher)), ); for (const ref of stringArray.references) { diff --git a/src/deobfuscator/controlFlowObject.ts b/packages/deobfuscate/src/control-flow-object.ts similarity index 84% rename from src/deobfuscator/controlFlowObject.ts rename to packages/deobfuscate/src/control-flow-object.ts index 406fea32..02df0c72 100644 --- a/src/deobfuscator/controlFlowObject.ts +++ b/packages/deobfuscate/src/control-flow-object.ts @@ -1,29 +1,31 @@ -import traverse, { Binding, NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import { FunctionExpression } from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../transforms'; -import mergeStrings from '../transforms/mergeStrings'; -import { getPropName } from '../utils/ast'; -import { inlineCfFunction } from '../utils/inline'; +import { Binding, NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import { FunctionExpression } from "@babel/types"; +import * as m from "@codemod/matchers"; import { + Transform, + applyTransform, constKey, constMemberExpression, createFunctionMatcher, findParent, + getPropName, + inlineCfFunction, isReadonlyObject, -} from '../utils/matcher'; +} from "@webcrack/ast-utils"; +import mergeStrings from "../../unminify/src/transforms/merge-strings"; /** * Explanation: https://excalidraw.com/#json=0vehUdrfSS635CNPEQBXl,hDOd-UO9ETfSDWT9MxVX-A */ export default { - name: 'controlFlowObject', - tags: ['safe'], + name: "controlFlowObject", + tags: ["safe"], + scope: true, visitor() { const varId = m.capture(m.identifier()); - const propertyName = m.matcher(name => /^[a-z]{5}$/i.test(name)); + const propertyName = m.matcher((name) => /^[a-z]{5}$/i.test(name)); const propertyKey = constKey(propertyName); const propertyValue = m.or( // E.g. "6|0|4|3|1|5|2" @@ -33,12 +35,12 @@ export default { m.returnStatement( m.or( m.binaryExpression(undefined, left, right), - m.logicalExpression(undefined, left, right) - ) + m.logicalExpression(undefined, left, right), + ), ), ]), // E.g. function (a, b, c) { return a(b, c) } with an arbitrary number of arguments - m.matcher(node => { + m.matcher((node) => { return ( t.isFunctionExpression(node) && createFunctionMatcher(node.params.length, (...params) => [ @@ -58,15 +60,15 @@ export default { m.returnStatement( m.callExpression(m.fromCapture(fnName), [ m.spreadElement(m.fromCapture(restName)), - ]) + ]), ), - ]) + ]), ); - })() + })(), ); // E.g. "rLxJs": "6|0|4|3|1|5|2" const objectProperties = m.capture( - m.arrayOf(m.objectProperty(propertyKey, propertyValue)) + m.arrayOf(m.objectProperty(propertyKey, propertyValue)), ); const aliasId = m.capture(m.identifier()); const aliasVar = m.variableDeclaration(m.anything(), [ @@ -79,25 +81,25 @@ export default { // E.g. obj.rLxJs = "6|0|4|3|1|5|2" const assignment = m.expressionStatement( m.assignmentExpression( - '=', + "=", constMemberExpression(m.fromCapture(varId), assignedKey), - assignedValue - ) + assignedValue, + ), ); const looseAssignment = m.expressionStatement( m.assignmentExpression( - '=', - constMemberExpression(m.fromCapture(varId), assignedKey) - ) + "=", + constMemberExpression(m.fromCapture(varId), assignedKey), + ), ); // E.g. obj.rLxJs const memberAccess = constMemberExpression( m.or(m.fromCapture(varId), m.fromCapture(aliasId)), - propertyName + propertyName, ); const varMatcher = m.variableDeclarator( varId, - m.capture(m.objectExpression(objectProperties)) + m.capture(m.objectExpression(objectProperties)), ); function isConstantBinding(binding: Binding) { @@ -117,10 +119,10 @@ export default { if (!isReadonlyObject(binding, memberAccess)) return changes; const props = new Map( - objectProperties.current!.map(p => [ + objectProperties.current!.map((p) => [ getPropName(p.key), p.value as t.FunctionExpression | t.StringLiteral, - ]) + ]), ); if (!props.size) return changes; @@ -128,7 +130,7 @@ export default { // Have to loop backwards because we might replace a node that // contains another reference to the binding (https://github.com/babel/babel/issues/12943) - [...binding.referencePaths].reverse().forEach(ref => { + [...binding.referencePaths].reverse().forEach((ref) => { const memberPath = ref.parentPath as NodePath; const propName = getPropName(memberPath.node.property)!; const value = props.get(propName)!; @@ -138,13 +140,13 @@ export default { } else { inlineCfFunction( value, - memberPath.parentPath as NodePath + memberPath.parentPath as NodePath, ); } changes++; }); - oldRefs.forEach(ref => { + oldRefs.forEach((ref) => { const varDeclarator = findParent(ref, m.variableDeclarator()); if (varDeclarator) changes += transform(varDeclarator); }); @@ -174,17 +176,15 @@ export default { // Example: _0x29d709["kHAOU"] = "5|1|2" + "|4|3|" + "0|6"; // For performance reasons, only traverse if it is a potential match (value doesn't matter) if (looseAssignment.match(statement)) { - traverse(statement, mergeStrings.visitor(), undefined, { - changes: 0, - }); + applyTransform(statement, mergeStrings); } if (assignment.match(statement)) { properties.push( t.objectProperty( t.identifier(assignedKey.current!), - assignedValue.current! - ) + assignedValue.current!, + ), ); } else { break; @@ -216,7 +216,6 @@ export default { this.changes += transform(path); }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/src/deobfuscator/controlFlowSwitch.ts b/packages/deobfuscate/src/control-flow-switch.ts similarity index 64% rename from src/deobfuscator/controlFlowSwitch.ts rename to packages/deobfuscate/src/control-flow-switch.ts index 4ea87265..cf8dcb77 100644 --- a/src/deobfuscator/controlFlowSwitch.ts +++ b/packages/deobfuscate/src/control-flow-switch.ts @@ -1,28 +1,31 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../transforms'; -import { constMemberExpression, infiniteLoop } from '../utils/matcher'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + Transform, + constMemberExpression, + infiniteLoop, +} from "@webcrack/ast-utils"; export default { - name: 'controlFlowSwitch', - tags: ['safe'], + name: "controlFlowSwitch", + tags: ["safe"], visitor() { const sequenceName = m.capture(m.identifier()); const sequenceString = m.capture( - m.matcher(s => /^\d+(\|\d+)*$/.test(s)) + m.matcher((s) => /^\d+(\|\d+)*$/.test(s)), ); const iterator = m.capture(m.identifier()); const cases = m.capture( m.arrayOf( m.switchCase( - m.stringLiteral(m.matcher(s => /^\d+$/.test(s))), + m.stringLiteral(m.matcher((s) => /^\d+$/.test(s))), m.anyList( m.zeroOrMore(), - m.or(m.continueStatement(), m.returnStatement()) - ) - ) - ) + m.or(m.continueStatement(), m.returnStatement()), + ), + ), + ), ); const matcher = m.blockStatement( @@ -32,9 +35,9 @@ export default { m.variableDeclarator( sequenceName, m.callExpression( - constMemberExpression(m.stringLiteral(sequenceString), 'split'), - [m.stringLiteral('|')] - ) + constMemberExpression(m.stringLiteral(sequenceString), "split"), + [m.stringLiteral("|")], + ), ), ]), // E.g. let iterator = 0 or -0x1a70 + 0x93d + 0x275 * 0x7 @@ -45,16 +48,16 @@ export default { // E.g. switch (sequence[iterator++]) { m.memberExpression( m.fromCapture(sequenceName), - m.updateExpression('++', m.fromCapture(iterator)), - true + m.updateExpression("++", m.fromCapture(iterator)), + true, ), - cases + cases, ), m.breakStatement(), - ]) + ]), ), - m.zeroOrMore() - ) + m.zeroOrMore(), + ), ); return { @@ -63,22 +66,21 @@ export default { if (!matcher.match(path.node)) return; const caseStatements = new Map( - cases.current!.map(c => [ + cases.current!.map((c) => [ (c.test as t.StringLiteral).value, t.isContinueStatement(c.consequent.at(-1)) ? c.consequent.slice(0, -1) : c.consequent, - ]) + ]), ); - const sequence = sequenceString.current!.split('|'); - const newStatements = sequence.flatMap(s => caseStatements.get(s)!); + const sequence = sequenceString.current!.split("|"); + const newStatements = sequence.flatMap((s) => caseStatements.get(s)!); path.node.body.splice(0, 3, ...newStatements); this.changes += newStatements.length + 3; }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/src/deobfuscator/deadCode.ts b/packages/deobfuscate/src/dead-code.ts similarity index 70% rename from src/deobfuscator/deadCode.ts rename to packages/deobfuscate/src/dead-code.ts index 3314d786..2f529419 100644 --- a/src/deobfuscator/deadCode.ts +++ b/packages/deobfuscate/src/dead-code.ts @@ -1,25 +1,25 @@ -import { NodePath, Scope } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../transforms'; -import { renameFast } from '../utils/rename'; +import { NodePath, Scope } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform, renameFast } from "@webcrack/ast-utils"; export default { - name: 'deadCode', - tags: ['unsafe'], + name: "deadCode", + tags: ["unsafe"], + scope: true, visitor() { const stringComparison = m.binaryExpression( - m.or('===', '==', '!==', '!='), + m.or("===", "==", "!==", "!="), + m.stringLiteral(), m.stringLiteral(), - m.stringLiteral() ); const testMatcher = m.or( stringComparison, - m.unaryExpression('!', stringComparison) + m.unaryExpression("!", stringComparison), ); return { - 'IfStatement|ConditionalExpression': { + "IfStatement|ConditionalExpression": { exit(_path) { const path = _path as NodePath< t.IfStatement | t.ConditionalExpression @@ -40,11 +40,11 @@ export default { } } - if (path.get('test').evaluateTruthy()) { - renameShadowedVariables(path.get('consequent').scope); + if (path.get("test").evaluateTruthy()) { + renameShadowedVariables(path.get("consequent").scope); replace(path, path.node.consequent); } else if (path.node.alternate) { - renameShadowedVariables(path.get('alternate').scope); + renameShadowedVariables(path.get("alternate").scope); replace(path, path.node.alternate); } else { path.remove(); @@ -53,7 +53,6 @@ export default { this.changes++; }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/src/deobfuscator/debugProtection.ts b/packages/deobfuscate/src/debug-protection.ts similarity index 80% rename from src/deobfuscator/debugProtection.ts rename to packages/deobfuscate/src/debug-protection.ts index de2aa14e..8a5ef97d 100644 --- a/src/deobfuscator/debugProtection.ts +++ b/packages/deobfuscate/src/debug-protection.ts @@ -1,7 +1,11 @@ -import * as m from '@codemod/matchers'; -import { ifStatement } from '@codemod/matchers'; -import { Transform } from '../transforms'; -import { constMemberExpression, findParent, iife } from '../utils/matcher'; +import * as m from "@codemod/matchers"; +import { ifStatement } from "@codemod/matchers"; +import { + Transform, + constMemberExpression, + findParent, + iife, +} from "@webcrack/ast-utils"; // https://github.com/javascript-obfuscator/javascript-obfuscator/blob/d7f73935557b2cd15a2f7cd0b01017d9cddbd015/src/custom-code-helpers/debug-protection/templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate.ts @@ -12,8 +16,9 @@ import { constMemberExpression, findParent, iife } from '../utils/matcher'; // https://github.com/javascript-obfuscator/javascript-obfuscator/blob/d7f73935557b2cd15a2f7cd0b01017d9cddbd015/src/custom-code-helpers/debug-protection/templates/debug-protection-function/DebuggerTemplateNoEval.ts export default { - name: 'debugProtection', - tags: ['safe'], + name: "debugProtection", + tags: ["safe"], + scope: true, visitor() { const ret = m.capture(m.identifier()); const debugProtectionFunctionName = m.capture(m.anyString()); @@ -26,19 +31,19 @@ export default { m.or( m.debuggerStatement(), m.callExpression( - constMemberExpression(m.anyExpression(), 'constructor'), - [m.stringLiteral('debugger')] - ) - ) - ) + constMemberExpression(m.anyExpression(), "constructor"), + [m.stringLiteral("debugger")], + ), + ), + ), ); // that.setInterval(debugProtectionFunctionName, 4000); const intervalCall = m.callExpression( - constMemberExpression(m.anyExpression(), 'setInterval'), + constMemberExpression(m.anyExpression(), "setInterval"), [ m.identifier(m.fromCapture(debugProtectionFunctionName)), m.numericLiteral(), - ] + ], ); // function debugProtectionFunctionName(ret) { @@ -55,10 +60,10 @@ export default { // debuggerProtection(++counter); m.expressionStatement( m.callExpression(m.fromCapture(debuggerProtection), [ - m.updateExpression('++', m.fromCapture(counter), true), - ]) + m.updateExpression("++", m.fromCapture(counter), true), + ]), ), - ]) + ]), ), m.tryStatement( m.blockStatement([ @@ -74,13 +79,13 @@ export default { m.expressionStatement( m.callExpression(m.fromCapture(debuggerProtection), [ m.numericLiteral(0), - ]) + ]), ), - ]) + ]), ), - ]) + ]), ), - ]) + ]), ); return { @@ -88,10 +93,10 @@ export default { if (!matcher.match(path.node)) return; const binding = path.scope.getBinding( - debugProtectionFunctionName.current! + debugProtectionFunctionName.current!, )!; - binding.referencePaths.forEach(ref => { + binding.referencePaths.forEach((ref) => { if (intervalCall.match(ref.parent)) { findParent(ref, iife)?.remove(); } @@ -99,7 +104,6 @@ export default { path.remove(); }, - noScope: true, }; }, } satisfies Transform; diff --git a/src/deobfuscator/decoder.ts b/packages/deobfuscate/src/decoder.ts similarity index 81% rename from src/deobfuscator/decoder.ts rename to packages/deobfuscate/src/decoder.ts index 55f87fc2..5c060b38 100644 --- a/src/deobfuscator/decoder.ts +++ b/packages/deobfuscate/src/decoder.ts @@ -1,10 +1,9 @@ -import { expression } from '@babel/template'; -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { findParent } from '../utils/matcher'; -import { renameFast } from '../utils/rename'; -import { StringArray } from './stringArray'; +import { expression } from "@babel/template"; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { findParent, renameFast } from "@webcrack/ast-utils"; +import { StringArray } from "./string-array"; /** * A function that is called with >= 1 numeric/string arguments @@ -26,20 +25,20 @@ export class Decoder { const argumentMatcher: m.Matcher = m.or( m.binaryExpression( m.anything(), - m.matcher(node => argumentMatcher.match(node)), - m.matcher(node => argumentMatcher.match(node)) + m.matcher((node) => argumentMatcher.match(node)), + m.matcher((node) => argumentMatcher.match(node)), ), m.unaryExpression( - '-', - m.matcher(node => argumentMatcher.match(node)) + "-", + m.matcher((node) => argumentMatcher.match(node)), ), m.numericLiteral(), - m.stringLiteral() + m.stringLiteral(), ); const call = m.callExpression( m.identifier(this.name), - m.arrayOf(argumentMatcher) + m.arrayOf(argumentMatcher), ); const conditional = m.capture(m.conditionalExpression()); @@ -59,7 +58,7 @@ export class Decoder { CALLEE: ref.parent.callee, CONSEQUENT: conditional.current!.consequent, ALTERNATE: conditional.current!.alternate, - }) + }), ); // some of the scope information is somehow lost after replacing replacement.scope.crawl(); @@ -87,18 +86,18 @@ export function findDecoders(stringArray: StringArray): Decoder[] { m.variableDeclaration(undefined, [ m.variableDeclarator( arrayIdentifier, - m.callExpression(m.identifier(stringArray.name)) + m.callExpression(m.identifier(stringArray.name)), ), ]), m.zeroOrMore(), // var h = array[e]; return h; // or return array[e -= 254]; m.containerOf( - m.memberExpression(m.fromCapture(arrayIdentifier), undefined, true) + m.memberExpression(m.fromCapture(arrayIdentifier), undefined, true), ), - m.zeroOrMore() - ) - ) + m.zeroOrMore(), + ), + ), ); for (const ref of stringArray.references) { diff --git a/packages/deobfuscate/src/index.ts b/packages/deobfuscate/src/index.ts new file mode 100644 index 00000000..bc1c91fd --- /dev/null +++ b/packages/deobfuscate/src/index.ts @@ -0,0 +1,69 @@ +import { + AsyncTransform, + applyTransform, + applyTransformAsync, + applyTransforms, +} from "@webcrack/ast-utils"; +import mergeStrings from "../../unminify/src/transforms/merge-strings"; +import { findArrayRotator } from "./array-rotator"; +import controlFlowObject from "./control-flow-object"; +import controlFlowSwitch from "./control-flow-switch"; +import deadCode from "./dead-code"; +import { findDecoders } from "./decoder"; +import inlineDecodedStrings from "./inline-decoded-strings"; +import inlineDecoderWrappers from "./inline-decoder-wappers"; +import inlineObjectProps from "./inline-object-props"; +import { findStringArray } from "./string-array"; +import { + Sandbox, + VMDecoder, + createBrowserSandbox, + createNodeSandbox, +} from "./vm"; + +export { createBrowserSandbox, createNodeSandbox, type Sandbox }; + +// https://astexplorer.net/#/gist/b1018df4a8daebfcb1daf9d61fe17557/4ff9ad0e9c40b9616956f17f59a2d9888cd62a4f + +export default { + name: "deobfuscate", + tags: ["unsafe"], + scope: true, + async run(ast, state, sandbox) { + if (!sandbox) return; + + const stringArray = findStringArray(ast); + if (!stringArray) return; + + const rotator = findArrayRotator(stringArray); + + const decoders = findDecoders(stringArray); + + state.changes += applyTransform(ast, inlineObjectProps).changes; + + for (const decoder of decoders) { + state.changes += applyTransform( + ast, + inlineDecoderWrappers, + decoder.path, + ).changes; + } + + const vm = new VMDecoder(sandbox, stringArray, decoders, rotator); + state.changes += ( + await applyTransformAsync(ast, inlineDecodedStrings, { vm }) + ).changes; + + stringArray.path.remove(); + rotator?.remove(); + decoders.forEach((decoder) => decoder.path.remove()); + state.changes += 2 + decoders.length; + + state.changes += applyTransforms(ast, [ + mergeStrings, + deadCode, + controlFlowObject, + controlFlowSwitch, + ]).changes; + }, +} satisfies AsyncTransform; diff --git a/src/deobfuscator/inlineDecodedStrings.ts b/packages/deobfuscate/src/inline-decoded-strings.ts similarity index 56% rename from src/deobfuscator/inlineDecodedStrings.ts rename to packages/deobfuscate/src/inline-decoded-strings.ts index eecb64ea..08eedafc 100644 --- a/src/deobfuscator/inlineDecodedStrings.ts +++ b/packages/deobfuscate/src/inline-decoded-strings.ts @@ -1,19 +1,20 @@ -import * as t from '@babel/types'; -import { AsyncTransform } from '../transforms'; -import { VMDecoder } from './vm'; +import * as t from "@babel/types"; +import { AsyncTransform } from "@webcrack/ast-utils"; +import { VMDecoder } from "./vm"; /** * Replaces calls to decoder functions with the decoded string. * E.g. `m(199)` -> `'log'` */ export default { - name: 'inlineDecodedStrings', - tags: ['unsafe'], + name: "inlineDecodedStrings", + tags: ["unsafe"], + scope: true, async run(ast, state, options) { if (!options) return; - const calls = options.vm.decoders.flatMap(decoder => - decoder.collectCalls() + const calls = options.vm.decoders.flatMap((decoder) => + decoder.collectCalls(), ); const decodedValues = await options.vm.decode(calls); @@ -22,8 +23,8 @@ export default { const value = decodedValues[i]; call.replaceWith(t.valueToNode(value)); - if (typeof value !== 'string') - call.addComment('leading', 'webcrack:decode_error'); + if (typeof value !== "string") + call.addComment("leading", "webcrack:decode_error"); } state.changes += calls.length; diff --git a/src/deobfuscator/inlineDecoderWrappers.ts b/packages/deobfuscate/src/inline-decoder-wappers.ts similarity index 66% rename from src/deobfuscator/inlineDecoderWrappers.ts rename to packages/deobfuscate/src/inline-decoder-wappers.ts index d4a1028d..4897d06b 100644 --- a/src/deobfuscator/inlineDecoderWrappers.ts +++ b/packages/deobfuscate/src/inline-decoder-wappers.ts @@ -1,14 +1,18 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import { Transform } from '../transforms'; -import { inlineFunctionAliases, inlineVariableAliases } from '../utils/inline'; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import { + Transform, + inlineFunctionAliases, + inlineVariableAliases, +} from "@webcrack/ast-utils"; /** * Replaces all references to `var alias = decode;` with `decode` */ export default { - name: 'inlineDecoderWrappers', - tags: ['unsafe'], + name: "inlineDecoderWrappers", + tags: ["unsafe"], + scope: true, run(ast, state, decoder) { if (!decoder?.node.id) return; diff --git a/src/deobfuscator/inlineObjectProps.ts b/packages/deobfuscate/src/inline-object-props.ts similarity index 74% rename from src/deobfuscator/inlineObjectProps.ts rename to packages/deobfuscate/src/inline-object-props.ts index 28b7a2cb..e8930bd4 100644 --- a/src/deobfuscator/inlineObjectProps.ts +++ b/packages/deobfuscate/src/inline-object-props.ts @@ -1,13 +1,13 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../transforms'; -import { getPropName } from '../utils/ast'; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; import { + Transform, constKey, constMemberExpression, + getPropName, isReadonlyObject, -} from '../utils/matcher'; +} from "@webcrack/ast-utils"; /** * Inline objects that only have string or numeric literal properties. @@ -27,29 +27,30 @@ import { * ``` */ export default { - name: 'inlineObjectProps', - tags: ['safe'], + name: "inline-object-props", + tags: ["safe"], + scope: true, visitor() { const varId = m.capture(m.identifier()); - const propertyName = m.matcher(name => /^[\w]+$/i.test(name)); + const propertyName = m.matcher((name) => /^[\w]+$/i.test(name)); const propertyKey = constKey(propertyName); // E.g. "_0x51b74a": 0x80 const objectProperties = m.capture( m.arrayOf( m.objectProperty( propertyKey, - m.or(m.stringLiteral(), m.numericLiteral()) - ) - ) + m.or(m.stringLiteral(), m.numericLiteral()), + ), + ), ); // E.g. obj._0x51b74a const memberAccess = constMemberExpression( m.fromCapture(varId), - propertyName + propertyName, ); const varMatcher = m.variableDeclarator( varId, - m.objectExpression(objectProperties) + m.objectExpression(objectProperties), ); return { @@ -61,14 +62,14 @@ export default { if (!binding || !isReadonlyObject(binding, memberAccess)) return; const props = new Map( - objectProperties.current!.map(p => [ + objectProperties.current!.map((p) => [ getPropName(p.key), p.value as t.StringLiteral | t.NumericLiteral, - ]) + ]), ); if ( - !binding.referencePaths.every(ref => { + !binding.referencePaths.every((ref) => { const memberPath = ref.parentPath as NodePath; const propName = getPropName(memberPath.node.property)!; return props.has(propName); @@ -76,7 +77,7 @@ export default { ) return; - binding.referencePaths.forEach(ref => { + binding.referencePaths.forEach((ref) => { const memberPath = ref.parentPath as NodePath; const propName = getPropName(memberPath.node.property)!; const value = props.get(propName)!; @@ -88,7 +89,6 @@ export default { path.remove(); this.changes++; }, - noScope: true, }; }, } satisfies Transform; diff --git a/packages/deobfuscate/src/matchers.d.ts b/packages/deobfuscate/src/matchers.d.ts new file mode 100644 index 00000000..01526964 --- /dev/null +++ b/packages/deobfuscate/src/matchers.d.ts @@ -0,0 +1,41 @@ +import { Matcher } from "@codemod/matchers"; + +type MatcherType = T extends Matcher ? U : T; + +declare module "@codemod/matchers" { + // The library only implements up to 5 arguments, but we need more + // Also have to keep the other ones because of recursive matchers (numberExpressions.ts) + + export function or(): Matcher; + export function or(first: Matcher | T): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + fifth: Matcher | X, + ): Matcher; + export function or( + ...matchers: T + ): Matcher>; +} + +declare module "@codemod/matchers/build/matchers/predicate" { + // Convenience overload for not having to cast the value when using it + export function predicate(predicate: (value: T) => boolean): Matcher; +} diff --git a/src/deobfuscator/mergeObjectAssignments.ts b/packages/deobfuscate/src/merge-object-assignments.ts similarity index 85% rename from src/deobfuscator/mergeObjectAssignments.ts rename to packages/deobfuscate/src/merge-object-assignments.ts index 9611ae75..c17348b4 100644 --- a/src/deobfuscator/mergeObjectAssignments.ts +++ b/packages/deobfuscate/src/merge-object-assignments.ts @@ -1,8 +1,7 @@ -import { Binding } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../transforms'; -import { constObjectProperty } from '../utils/matcher'; +import { Binding } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform, constObjectProperty } from "@webcrack/ast-utils"; /** * Merges object assignments into the object expression. @@ -17,8 +16,9 @@ import { constObjectProperty } from '../utils/matcher'; * ``` */ export default { - name: 'mergeObjectAssignments', - tags: ['safe'], + name: "merge-object-assignments", + tags: ["safe"], + scope: true, visitor: () => { const id = m.capture(m.identifier()); const object = m.capture(m.objectExpression([])); @@ -32,10 +32,10 @@ export default { // Example: obj.foo = 'bar'; const assignmentMatcher = m.expressionStatement( m.assignmentExpression( - '=', + "=", m.memberExpression(m.fromCapture(id), key, computed), - value - ) + value, + ), ); return { @@ -62,12 +62,12 @@ export default { // { [1]: value, "foo bar": value } can be simplified to { 1: value, "foo bar": value } const isComputed = computed.current! && - key.current!.type !== 'NumericLiteral' && - key.current!.type !== 'StringLiteral'; + key.current!.type !== "NumericLiteral" && + key.current!.type !== "StringLiteral"; // Example: const obj = { x: 1 }; obj.foo = 'bar'; -> const obj = { x: 1, foo: 'bar' }; object.current!.properties.push( - t.objectProperty(key.current!, value.current!, isComputed) + t.objectProperty(key.current!, value.current!, isComputed), ); sibling.remove(); @@ -96,7 +96,7 @@ export default { function hasCircularReference(node: t.Node, binding: Binding) { return ( // obj.foo = obj; - binding.referencePaths.some(path => path.find(p => p.node === node)) || + binding.referencePaths.some((path) => path.find((p) => p.node === node)) || // obj.foo = fn(); where fn could reference the binding or not, for simplicity we assume it does. m.containerOf(m.callExpression()).match(node) ); @@ -107,10 +107,10 @@ function hasCircularReference(node: t.Node, binding: Binding) { * might be different in the place the object will be inlined. */ const inlineableObject: m.Matcher = m.matcher( - node => + (node) => (t.isLiteral(node) && !t.isTemplateLiteral(node)) || m.arrayExpression(m.arrayOf(inlineableObject)).match(node) || m .objectExpression(m.arrayOf(constObjectProperty(inlineableObject))) - .match(node) + .match(node), ); diff --git a/src/deobfuscator/selfDefending.ts b/packages/deobfuscate/src/self-defending.ts similarity index 83% rename from src/deobfuscator/selfDefending.ts rename to packages/deobfuscate/src/self-defending.ts index 2e36e39a..16659e5d 100644 --- a/src/deobfuscator/selfDefending.ts +++ b/packages/deobfuscate/src/self-defending.ts @@ -1,15 +1,15 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../transforms'; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; import { + Transform, constMemberExpression, emptyIife, falseMatcher, findParent, matchIife, trueMatcher, -} from '../utils/matcher'; +} from "@webcrack/ast-utils"; // SingleCallController: https://github.com/javascript-obfuscator/javascript-obfuscator/blob/d7f73935557b2cd15a2f7cd0b01017d9cddbd015/src/custom-code-helpers/common/templates/SingleCallControllerTemplate.ts @@ -20,8 +20,9 @@ import { // debug protection function call: https://github.com/javascript-obfuscator/javascript-obfuscator/blob/d7f73935557b2cd15a2f7cd0b01017d9cddbd015/src/custom-code-helpers/debug-protection/templates/debug-protection-function-call/DebugProtectionFunctionCallTemplate.ts export default { - name: 'selfDefending', - tags: ['safe'], + name: "selfDefending", + tags: ["safe"], + scope: true, visitor() { const callController = m.capture(m.anyString()); const firstCall = m.capture(m.identifier()); @@ -65,48 +66,48 @@ export default { m.callExpression( constMemberExpression( m.fromCapture(fn), - 'apply' + "apply", ), [ m.fromCapture(context), - m.identifier('arguments'), - ] - ) + m.identifier("arguments"), + ], + ), ), ]), // fn = null; m.expressionStatement( m.assignmentExpression( - '=', + "=", m.fromCapture(fn), - m.nullLiteral() - ) + m.nullLiteral(), + ), ), // return res; m.returnStatement(m.fromCapture(res)), - ]) + ]), ), - ]) + ]), ), // : function() {} - m.functionExpression(null, [], m.blockStatement([])) - ) + m.functionExpression(null, [], m.blockStatement([])), + ), ), ]), // firstCall = false; m.expressionStatement( m.assignmentExpression( - '=', + "=", m.fromCapture(firstCall), - falseMatcher - ) + falseMatcher, + ), ), // return rfn; m.returnStatement(m.fromCapture(rfn)), - ]) - ) + ]), + ), ), - ]) + ]), ); return { @@ -117,9 +118,9 @@ export default { // ^ path/binding binding.referencePaths - .filter(ref => ref.parent.type === 'CallExpression') - .forEach(ref => { - if (ref.parentPath?.parent.type === 'CallExpression') { + .filter((ref) => ref.parent.type === "CallExpression") + .forEach((ref) => { + if (ref.parentPath?.parent.type === "CallExpression") { // callControllerFunctionName(this, function () { ... })(); // ^ ref ref.parentPath.parentPath?.remove(); @@ -138,7 +139,6 @@ export default { path.remove(); this.changes++; }, - noScope: true, }; }, } satisfies Transform; @@ -147,17 +147,17 @@ function removeSelfDefendingRefs(path: NodePath) { const varName = m.capture(m.anyString()); const varMatcher = m.variableDeclarator( m.identifier(varName), - m.callExpression(m.identifier(path.node.name)) + m.callExpression(m.identifier(path.node.name)), ); const callMatcher = m.expressionStatement( - m.callExpression(m.identifier(m.fromCapture(varName)), []) + m.callExpression(m.identifier(m.fromCapture(varName)), []), ); const varDecl = findParent(path, varMatcher); if (varDecl) { const binding = varDecl.scope.getBinding(varName.current!); - binding?.referencePaths.forEach(ref => { + binding?.referencePaths.forEach((ref) => { if (callMatcher.match(ref.parentPath?.parent)) ref.parentPath?.parentPath?.remove(); }); diff --git a/src/deobfuscator/stringArray.ts b/packages/deobfuscate/src/string-array.ts similarity index 83% rename from src/deobfuscator/stringArray.ts rename to packages/deobfuscate/src/string-array.ts index 82b8cbb9..4cca033f 100644 --- a/src/deobfuscator/stringArray.ts +++ b/packages/deobfuscate/src/string-array.ts @@ -1,9 +1,11 @@ -import traverse, { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { inlineArrayElements } from '../utils/inline'; -import { isReadonlyObject } from '../utils/matcher'; -import { renameFast } from '../utils/rename'; +import traverse, { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + inlineArrayElements, + isReadonlyObject, + renameFast, +} from "@webcrack/ast-utils"; export interface StringArray { path: NodePath; @@ -17,17 +19,17 @@ export function findStringArray(ast: t.Node): StringArray | undefined { const functionName = m.capture(m.anyString()); const arrayIdentifier = m.capture(m.identifier()); const arrayExpression = m.capture( - m.arrayExpression(m.arrayOf(m.stringLiteral())) + m.arrayExpression(m.arrayOf(m.stringLiteral())), ); // getStringArray = function () { return n; }; const functionAssignment = m.assignmentExpression( - '=', + "=", m.identifier(m.fromCapture(functionName)), m.functionExpression( undefined, [], - m.blockStatement([m.returnStatement(m.fromCapture(arrayIdentifier))]) - ) + m.blockStatement([m.returnStatement(m.fromCapture(arrayIdentifier))]), + ), ); const variableDeclaration = m.variableDeclaration(undefined, [ m.variableDeclarator(arrayIdentifier, arrayExpression), @@ -50,8 +52,8 @@ export function findStringArray(ast: t.Node): StringArray | undefined { variableDeclaration, m.expressionStatement(functionAssignment), m.returnStatement(m.callExpression(m.identifier(functionName))), - ]) - ) + ]), + ), ); traverse(ast, { @@ -61,12 +63,12 @@ export function findStringArray(ast: t.Node): StringArray | undefined { const length = arrayExpression.current!.elements.length; const name = functionName.current!; const binding = path.scope.getBinding(name)!; - renameFast(binding, '__STRING_ARRAY__'); + renameFast(binding, "__STRING_ARRAY__"); result = { path, references: binding.referencePaths, - name: '__STRING_ARRAY__', + name: "__STRING_ARRAY__", length, }; path.stop(); @@ -81,7 +83,7 @@ export function findStringArray(ast: t.Node): StringArray | undefined { const binding = path.scope.getBinding(arrayIdentifier.current!.name)!; const memberAccess = m.memberExpression( m.fromCapture(arrayIdentifier), - m.numericLiteral(m.matcher(value => value < length)) + m.numericLiteral(m.matcher((value) => value < length)), ); if (!isReadonlyObject(binding, memberAccess)) return; diff --git a/src/deobfuscator/vm.ts b/packages/deobfuscate/src/vm.ts similarity index 64% rename from src/deobfuscator/vm.ts rename to packages/deobfuscate/src/vm.ts index 5664fd32..4fe47b29 100644 --- a/src/deobfuscator/vm.ts +++ b/packages/deobfuscate/src/vm.ts @@ -1,10 +1,9 @@ -import { NodePath } from '@babel/traverse'; -import { CallExpression } from '@babel/types'; -import debug from 'debug'; -import { generate } from '../utils/generator'; -import { ArrayRotator } from './arrayRotator'; -import { Decoder } from './decoder'; -import { StringArray } from './stringArray'; +import { NodePath } from "@babel/traverse"; +import { CallExpression } from "@babel/types"; +import { generate } from "@webcrack/ast-utils"; +import { ArrayRotator } from "./array-rotator"; +import { Decoder } from "./decoder"; +import { StringArray } from "./string-array"; export type Sandbox = (code: string) => Promise; @@ -12,13 +11,13 @@ export function createNodeSandbox(): Sandbox { return async (code: string) => { const { default: { Isolate }, - } = await import('isolated-vm'); + } = await import("isolated-vm"); const isolate = new Isolate(); const context = await isolate.createContext(); const result = (await context.eval(code, { timeout: 10_000, copy: true, - filename: 'file:///obfuscated.js', + filename: "file:///obfuscated.js", })) as unknown; context.release(); isolate.dispose(); @@ -29,7 +28,7 @@ export function createNodeSandbox(): Sandbox { export function createBrowserSandbox(): Sandbox { return () => { // TODO: use sandybox (not available in web workers though) - throw new Error('Custom Sandbox implementation required.'); + throw new Error("Custom Sandbox implementation required."); }; } @@ -42,7 +41,7 @@ export class VMDecoder { sandbox: Sandbox, stringArray: StringArray, decoders: Decoder[], - rotator?: ArrayRotator + rotator?: ArrayRotator, ) { this.sandbox = sandbox; this.decoders = decoders; @@ -54,26 +53,21 @@ export class VMDecoder { shouldPrintComment: () => false, }; const stringArrayCode = generate(stringArray.path.node, generateOptions); - const rotatorCode = rotator ? generate(rotator.node, generateOptions) : ''; + const rotatorCode = rotator ? generate(rotator.node, generateOptions) : ""; const decoderCode = decoders - .map(decoder => generate(decoder.path.node, generateOptions)) - .join(';\n'); + .map((decoder) => generate(decoder.path.node, generateOptions)) + .join(";\n"); - this.setupCode = [stringArrayCode, rotatorCode, decoderCode].join(';\n'); + this.setupCode = [stringArrayCode, rotatorCode, decoderCode].join(";\n"); } async decode(calls: NodePath[]): Promise { const code = `(() => { ${this.setupCode} - return [${calls.join(',')}] + return [${calls.join(",")}] })()`; - try { - const result = await this.sandbox(code); - return result as unknown[]; - } catch (err) { - debug('webcrack:deobfuscate')('vm code:', code); - throw err; - } + const result = await this.sandbox(code); + return result as unknown[]; } } diff --git a/test/__snapshots__/deobfuscator.test.ts.snap b/packages/deobfuscate/test/__snapshots__/deobfuscate.test.ts.snap similarity index 100% rename from test/__snapshots__/deobfuscator.test.ts.snap rename to packages/deobfuscate/test/__snapshots__/deobfuscate.test.ts.snap diff --git a/packages/deobfuscate/test/__snapshots__/deobfuscator.test.ts.snap b/packages/deobfuscate/test/__snapshots__/deobfuscator.test.ts.snap new file mode 100644 index 00000000..8b0a189e --- /dev/null +++ b/packages/deobfuscate/test/__snapshots__/deobfuscator.test.ts.snap @@ -0,0 +1,159 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`deobfuscate obfuscator.io.js 1`] = ` +"// v4.0.0 + +function hi() { + console.log(\\"Hello World!\\"); + console.log( /*webcrack:decode_error*/undefined); + console.log( /*webcrack:decode_error*/undefined); + const p = true; + console.log(p ? \\"log\\" : \\"Hello World!\\"); +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-calls-transform.js 1`] = ` +"function foo() { + var c = \\"string1\\"; + var d = \\"string2\\"; + var e = \\"string3\\"; + var f = \\"string4\\"; + var g = \\"string5\\"; + var h = \\"string6\\"; +} +console.log(foo());" +`; + +exports[`deobfuscate obfuscator.io-control-flow.js 1`] = ` +"function applyTransforms() { + this.modules.forEach(varInjection_1.inlineVarInjections); + this.modules.forEach(esm_1.convertESM); + (0, getDefaultExport_1.convertDefaultRequire)(this); + this.replaceRequireCalls(); + var f = m.capture(m.numericLiteral()); + var g = m.callExpression(m.identifier(\\"require\\"), [f]); + return g; +}" +`; + +exports[`deobfuscate obfuscator.io-control-flow-keys.js 1`] = ` +"function hi() { + const _0x46643e = 1; + const _0x4d295f = 2; + if (_0x46643e < _0x4d295f) { + console.log(\\"Hello World!\\"); + } +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-control-flow-partial-keys.js 1`] = ` +"function hi() { + const _0x46643e = 1; + const _0x4d295f = 2; + if (_0x46643e < _0x4d295f) { + console.log(\\"Hello World!\\"); + } +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-control-flow-split-strings.js 1`] = ` +"function _0x225c6a() { + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); +} +_0x225c6a();" +`; + +exports[`deobfuscate obfuscator.io-control-flow-spread.js 1`] = ` +"function hi() { + return m.functionExpression(undefined, captures.map(m.identifier), m.blockStatement(body(...captures.map(_0x56f63c => m.identifier(m.fromCapture(_0x56f63c))), ...arr))); +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-control-flow-switch-return.js 1`] = ` +"function hi() { + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + console.log(\\"Hello World!\\"); + return { + x: 1 + }; +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-function-wrapper.js 1`] = ` +"function hi() { + console.log(\\"Hello World!\\"); + console.log(30); + console.log(undefined); + function notAWrapper(c, d) { + return \\"log\\"; + } + console.log(notAWrapper(foo(), bar())); +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-high.js 1`] = ` +"function hi() { + console.log(\\"Hello World!\\"); +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-multi-encoders.js 1`] = ` +"function hi() { + console.log(\\"Hello World!\\"); +} +hi();" +`; + +exports[`deobfuscate obfuscator.io-rotator-unary.js 1`] = ` +"function hi() { + console.log(\\"Hello World!\\"); +} +hi();" +`; + +exports[`deobfuscate simple-string-array.js 1`] = ` +"console.log(\\"Hello, World!\\"); + +// ignore mutable array +const arr2 = [\\"log\\", \\"Hello, World!\\"]; +arr2[0] = \\"warn\\"; +console[arr2[0]](arr2[1]);" +`; + +exports[`inline decoder > inline function 1`] = ` +"function decoder() {} +decoder(1); +(() => { + decoder(2 - 625, 3); + (() => { + decoder(5 - -678 - 625, 4); + })(); +})();" +`; + +exports[`inline decoder > inline variable 1`] = ` +"function decoder() {} +decoder(1); +() => { + decoder(2); + decoder(3); + () => { + alias(4); + }; + decoder(5); +};" +`; diff --git a/packages/deobfuscate/test/deobfuscate.test.ts b/packages/deobfuscate/test/deobfuscate.test.ts new file mode 100644 index 00000000..e9cbdae1 --- /dev/null +++ b/packages/deobfuscate/test/deobfuscate.test.ts @@ -0,0 +1,90 @@ +import { parse } from "@babel/parser"; +import traverse from "@babel/traverse"; +import { + generate, + inlineFunctionAliases, + inlineVariableAliases, +} from "@webcrack/ast-utils"; +import { readFile } from "fs/promises"; +import { join } from "node:path"; +import { describe, expect, test } from "vitest"; +import { webcrack } from "../../webcrack/src/index"; + +// Test samples +test.each([ + "obfuscator.io.js", + "obfuscator.io-rotator-unary.js", + "obfuscator.io-multi-encoders.js", + "obfuscator.io-function-wrapper.js", + "obfuscator.io-calls-transform.js", + "obfuscator.io-control-flow.js", + "obfuscator.io-control-flow-split-strings.js", + "obfuscator.io-control-flow-keys.js", + "obfuscator.io-control-flow-partial-keys.js", + "obfuscator.io-control-flow-switch-return.js", + "obfuscator.io-control-flow-spread.js", + "obfuscator.io-high.js", + "simple-string-array.js", +])("deobfuscate %s", async (filename) => { + const result = await webcrack( + await readFile(join(__dirname, "samples", filename), "utf8"), + ); + expect(result.code).toMatchSnapshot(); +}); + +describe("inline decoder", () => { + test("inline variable", () => { + const ast = parse(` + function decoder() {} + decoder(1); + (() => { + const alias = decoder, alias3 = alias; + alias(2); + alias3(3); + (() => { + let alias2; + (alias2 = alias)(4); + }); + let alias4; + alias4 = alias; + alias4(5); + }); + `); + traverse(ast, { + FunctionDeclaration(path) { + const binding = path.scope.getBinding("decoder")!; + inlineVariableAliases(binding); + path.stop(); + }, + }); + expect(generate(ast)).toMatchSnapshot(); + }); + + test("inline function", () => { + const ast = parse(` + function decoder() {} + decoder(1); + (() => { + function alias(a, b) { + return decoder(a - 625, b); + } + alias(2, 3); + (() => { + function alias2(a, b) { + return alias(b - -678, a); + } + alias2(4, 5); + })(); + })(); + `); + traverse(ast, { + FunctionDeclaration(path) { + const binding = path.scope.parent.bindings.decoder; + inlineFunctionAliases(binding); + path.stop(); + }, + }); + + expect(generate(ast)).toMatchSnapshot(); + }); +}); diff --git a/packages/deobfuscate/test/index.ts b/packages/deobfuscate/test/index.ts new file mode 100644 index 00000000..38479fab --- /dev/null +++ b/packages/deobfuscate/test/index.ts @@ -0,0 +1,14 @@ +import { parse } from "@babel/parser"; +import { Transform, applyTransform } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +export function testTransform(transform: Transform) { + return (input: string, options?: Options) => { + const ast = parse(input, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + }); + applyTransform(ast, transform, options); + return expect(ast); + }; +} diff --git a/packages/deobfuscate/test/inline-object-props.test.ts b/packages/deobfuscate/test/inline-object-props.test.ts new file mode 100644 index 00000000..8d572de7 --- /dev/null +++ b/packages/deobfuscate/test/inline-object-props.test.ts @@ -0,0 +1,119 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import inlineObjectProps from "../src/inline-object-props"; + +const expectJS = testTransform(inlineObjectProps); + +test("inline property", () => + expectJS(` + const a = { x: 1 }; + console.log(a.x); + `).toMatchInlineSnapshot("console.log(1);")); + +test("ignore non-existent properties", () => + expectJS(` + const a = { x: 1 }; + console.log(a.__defineGetter__); + `).toMatchInlineSnapshot(` + const a = { + x: 1 + }; + console.log(a.__defineGetter__); + `)); + +test("ignore shared variable references", () => + expectJS(` + const a = { x: 1 }; + fn(a); + console.log(a.x); + `).toMatchInlineSnapshot(` + const a = { + x: 1 + }; + fn(a); + console.log(a.x); + `)); + +test("ignore variable assignment", () => + expectJS(` + let a = { x: 1 }; + a = { x: 2 }; + console.log(a.x); + `).toMatchInlineSnapshot(` + let a = { + x: 1 + }; + a = { + x: 2 + }; + console.log(a.x); + `)); + +test("ignore property assignment", () => + expectJS(` + const a = { x: 1 }; + a.x = 2; + console.log(a.x); + `).toMatchInlineSnapshot(` + const a = { + x: 1 + }; + a.x = 2; + console.log(a.x); + `)); + +test("ignore property assignment with array pattern", () => + expectJS(` + let a = { x: 1 }; + [a.x] = [2]; + console.log(a.x); + `).toMatchInlineSnapshot(` + let a = { + x: 1 + }; + [a.x] = [2]; + console.log(a.x); + `)); + +test("ignore property assignment with object pattern", () => + expectJS(` + let a = { x: 1 }; + ({ x: a.x } = { x: 2 }); + console.log(a.x); + `).toMatchInlineSnapshot(` + let a = { + x: 1 + }; + ({ + x: a.x + } = { + x: 2 + }); + console.log(a.x); + `)); + +test("ignore delete", () => + expectJS(` + const a = { x: 1 }; + delete a.x; + console.log(a.x); + `).toMatchInlineSnapshot(` + const a = { + x: 1 + }; + delete a.x; + console.log(a.x); + `)); + +test("ignore update expression", () => + expectJS(` + const a = { x: 1 }; + a.x++; + console.log(a.x); + `).toMatchInlineSnapshot(` + const a = { + x: 1 + }; + a.x++; + console.log(a.x); + `)); diff --git a/packages/deobfuscate/test/merge-object-assignments.test.ts b/packages/deobfuscate/test/merge-object-assignments.test.ts new file mode 100644 index 00000000..3031638c --- /dev/null +++ b/packages/deobfuscate/test/merge-object-assignments.test.ts @@ -0,0 +1,63 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import mergeObjectAssignments from "../src/merge-object-assignments"; + +const expectJS = testTransform(mergeObjectAssignments); + +test("inline properties without inlining object", () => + expectJS(` + const obj = {}; + obj.foo = foo; + obj.bar = 1; + foo++; + return obj; + `).toMatchInlineSnapshot(` + const obj = { + foo: foo, + bar: 1 + }; + foo++; + return obj; + `)); + +test("inline properties and object", () => + expectJS(` + const obj = {}; + obj.foo = 'foo'; + return obj; + `).toMatchInlineSnapshot(` + return { + foo: 'foo' + }; + `)); + +test("computed properties", () => + expectJS(` + const obj = {}; + obj["a b c"] = 1; + obj[1] = 2; + return obj; + `).toMatchInlineSnapshot(` + return { + "a b c": 1, + 1: 2 + }; + `)); + +test("ignore circular reference", () => + expectJS(` + const obj = {}; + obj.foo = obj; + `).toMatchInlineSnapshot(` + const obj = {}; + obj.foo = obj; + `)); + +test("ignore call with possible circular reference", () => + expectJS(` + const obj = {}; + obj.foo = fn(); + `).toMatchInlineSnapshot(` + const obj = {}; + obj.foo = fn(); + `)); diff --git a/test/samples/obfuscator.io-calls-transform.js b/packages/deobfuscate/test/samples/obfuscator.io-calls-transform.js similarity index 100% rename from test/samples/obfuscator.io-calls-transform.js rename to packages/deobfuscate/test/samples/obfuscator.io-calls-transform.js diff --git a/test/samples/obfuscator.io-control-flow-keys.js b/packages/deobfuscate/test/samples/obfuscator.io-control-flow-keys.js similarity index 100% rename from test/samples/obfuscator.io-control-flow-keys.js rename to packages/deobfuscate/test/samples/obfuscator.io-control-flow-keys.js diff --git a/test/samples/obfuscator.io-control-flow-partial-keys.js b/packages/deobfuscate/test/samples/obfuscator.io-control-flow-partial-keys.js similarity index 100% rename from test/samples/obfuscator.io-control-flow-partial-keys.js rename to packages/deobfuscate/test/samples/obfuscator.io-control-flow-partial-keys.js diff --git a/test/samples/obfuscator.io-control-flow-split-strings.js b/packages/deobfuscate/test/samples/obfuscator.io-control-flow-split-strings.js similarity index 100% rename from test/samples/obfuscator.io-control-flow-split-strings.js rename to packages/deobfuscate/test/samples/obfuscator.io-control-flow-split-strings.js diff --git a/test/samples/obfuscator.io-control-flow-spread.js b/packages/deobfuscate/test/samples/obfuscator.io-control-flow-spread.js similarity index 100% rename from test/samples/obfuscator.io-control-flow-spread.js rename to packages/deobfuscate/test/samples/obfuscator.io-control-flow-spread.js diff --git a/test/samples/obfuscator.io-control-flow-switch-return.js b/packages/deobfuscate/test/samples/obfuscator.io-control-flow-switch-return.js similarity index 100% rename from test/samples/obfuscator.io-control-flow-switch-return.js rename to packages/deobfuscate/test/samples/obfuscator.io-control-flow-switch-return.js diff --git a/test/samples/obfuscator.io-control-flow.js b/packages/deobfuscate/test/samples/obfuscator.io-control-flow.js similarity index 100% rename from test/samples/obfuscator.io-control-flow.js rename to packages/deobfuscate/test/samples/obfuscator.io-control-flow.js diff --git a/test/samples/obfuscator.io-function-wrapper.js b/packages/deobfuscate/test/samples/obfuscator.io-function-wrapper.js similarity index 100% rename from test/samples/obfuscator.io-function-wrapper.js rename to packages/deobfuscate/test/samples/obfuscator.io-function-wrapper.js diff --git a/test/samples/obfuscator.io-high.js b/packages/deobfuscate/test/samples/obfuscator.io-high.js similarity index 100% rename from test/samples/obfuscator.io-high.js rename to packages/deobfuscate/test/samples/obfuscator.io-high.js diff --git a/test/samples/obfuscator.io-multi-encoders.js b/packages/deobfuscate/test/samples/obfuscator.io-multi-encoders.js similarity index 100% rename from test/samples/obfuscator.io-multi-encoders.js rename to packages/deobfuscate/test/samples/obfuscator.io-multi-encoders.js diff --git a/test/samples/obfuscator.io-rotator-unary.js b/packages/deobfuscate/test/samples/obfuscator.io-rotator-unary.js similarity index 100% rename from test/samples/obfuscator.io-rotator-unary.js rename to packages/deobfuscate/test/samples/obfuscator.io-rotator-unary.js diff --git a/test/samples/obfuscator.io.js b/packages/deobfuscate/test/samples/obfuscator.io.js similarity index 100% rename from test/samples/obfuscator.io.js rename to packages/deobfuscate/test/samples/obfuscator.io.js diff --git a/test/samples/simple-string-array.js b/packages/deobfuscate/test/samples/simple-string-array.js similarity index 100% rename from test/samples/simple-string-array.js rename to packages/deobfuscate/test/samples/simple-string-array.js diff --git a/packages/deobfuscate/test/setup.ts b/packages/deobfuscate/test/setup.ts new file mode 100644 index 00000000..f50b672e --- /dev/null +++ b/packages/deobfuscate/test/setup.ts @@ -0,0 +1,8 @@ +import * as t from "@babel/types"; +import { generate } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +expect.addSnapshotSerializer({ + test: (val: unknown) => t.isNode(val) && !("parentPath" in val), + serialize: (val: t.Node) => generate(val), +}); diff --git a/packages/deobfuscate/tsconfig.json b/packages/deobfuscate/tsconfig.json new file mode 100644 index 00000000..fca8f92b --- /dev/null +++ b/packages/deobfuscate/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@webcrack/typescript-config/base.json", +} diff --git a/packages/deobfuscate/vitest.config.ts b/packages/deobfuscate/vitest.config.ts new file mode 100644 index 00000000..cd893d71 --- /dev/null +++ b/packages/deobfuscate/vitest.config.ts @@ -0,0 +1,11 @@ +import { join } from "node:path"; +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + root: join(__dirname, "test"), + setupFiles: "setup.ts", + include: ["**/*.test.ts"], + isolate: false, + }, +}); diff --git a/packages/unminify/.eslintrc.cjs b/packages/unminify/.eslintrc.cjs new file mode 100644 index 00000000..d0f2c30e --- /dev/null +++ b/packages/unminify/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], +}; diff --git a/packages/unminify/package.json b/packages/unminify/package.json new file mode 100644 index 00000000..703f9650 --- /dev/null +++ b/packages/unminify/package.json @@ -0,0 +1,33 @@ +{ + "name": "@webcrack/unminify", + "version": "1.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "lint": "eslint src test", + "lint:fix": "eslint src test --fix", + "test": "vitest" + }, + "exports": { + ".": "./src/index.ts", + "./transforms": "./src/transforms/index.ts" + }, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "@codemod/matchers": "^1.7.0", + "@webcrack/ast-utils": "workspace:*" + }, + "devDependencies": { + "@types/babel__generator": "^7.6.7", + "@types/babel__helper-validator-identifier": "^7.15.2", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.20.4", + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "typescript": "^5.3.2" + } +} diff --git a/packages/unminify/src/index.ts b/packages/unminify/src/index.ts new file mode 100644 index 00000000..88762e1f --- /dev/null +++ b/packages/unminify/src/index.ts @@ -0,0 +1,29 @@ +import { parse } from "@babel/parser"; +import { + applyTransform, + applyTransforms, + generate, + Transform, +} from "@webcrack/ast-utils"; +import * as transforms from "./transforms"; + +export const unminify = { + name: "unminify", + tags: ["safe"], + scope: true, + run(ast, state) { + state.changes += applyTransforms(ast, Object.values(transforms)).changes; + }, +} satisfies Transform; + +export function unminifySource(code: string): string { + const ast = parse(code, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + plugins: ["jsx"], + }); + + applyTransform(ast, unminify); + + return generate(ast); +} diff --git a/packages/unminify/src/matchers.d.ts b/packages/unminify/src/matchers.d.ts new file mode 100644 index 00000000..01526964 --- /dev/null +++ b/packages/unminify/src/matchers.d.ts @@ -0,0 +1,41 @@ +import { Matcher } from "@codemod/matchers"; + +type MatcherType = T extends Matcher ? U : T; + +declare module "@codemod/matchers" { + // The library only implements up to 5 arguments, but we need more + // Also have to keep the other ones because of recursive matchers (numberExpressions.ts) + + export function or(): Matcher; + export function or(first: Matcher | T): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + fifth: Matcher | X, + ): Matcher; + export function or( + ...matchers: T + ): Matcher>; +} + +declare module "@codemod/matchers/build/matchers/predicate" { + // Convenience overload for not having to cast the value when using it + export function predicate(predicate: (value: T) => boolean): Matcher; +} diff --git a/src/transforms/blockStatement.ts b/packages/unminify/src/transforms/block-statements.ts similarity index 89% rename from src/transforms/blockStatement.ts rename to packages/unminify/src/transforms/block-statements.ts index d4d9cbf9..558a1ce9 100644 --- a/src/transforms/blockStatement.ts +++ b/packages/unminify/src/transforms/block-statements.ts @@ -1,9 +1,9 @@ -import * as t from '@babel/types'; -import { Transform } from '.'; +import * as t from "@babel/types"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'blockStatement', - tags: ['safe'], + name: "block-statements", + tags: ["safe"], visitor: () => ({ IfStatement: { exit(path) { @@ -44,6 +44,5 @@ export default { } }, }, - noScope: true, }), } satisfies Transform; diff --git a/src/transforms/computedProperties.ts b/packages/unminify/src/transforms/computed-properties.ts similarity index 66% rename from src/transforms/computedProperties.ts rename to packages/unminify/src/transforms/computed-properties.ts index cad4bf7b..d510eb3f 100644 --- a/src/transforms/computedProperties.ts +++ b/packages/unminify/src/transforms/computed-properties.ts @@ -1,28 +1,28 @@ -import { isIdentifierName } from '@babel/helper-validator-identifier'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import { isIdentifierName } from "@babel/helper-validator-identifier"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'computedProperties', - tags: ['safe'], + name: "computed-properties", + tags: ["safe"], visitor() { const stringMatcher = m.capture( - m.stringLiteral(m.matcher(value => isIdentifierName(value))) + m.stringLiteral(m.matcher((value) => isIdentifierName(value))), ); const propertyMatcher = m.or( m.memberExpression(m.anything(), stringMatcher, true), - m.optionalMemberExpression(m.anything(), stringMatcher, true) + m.optionalMemberExpression(m.anything(), stringMatcher, true), ); const keyMatcher = m.or( m.objectProperty(stringMatcher), m.classProperty(stringMatcher), m.objectMethod(undefined, stringMatcher), - m.classMethod(undefined, stringMatcher) + m.classMethod(undefined, stringMatcher), ); return { - 'MemberExpression|OptionalMemberExpression': { + "MemberExpression|OptionalMemberExpression": { exit(path) { if (propertyMatcher.match(path.node)) { path.node.computed = false; @@ -31,7 +31,7 @@ export default { } }, }, - 'ObjectProperty|ClassProperty|ObjectMethod|ClassMethod': { + "ObjectProperty|ClassProperty|ObjectMethod|ClassMethod": { exit(path) { if (keyMatcher.match(path.node)) { path.node.computed = false; @@ -40,7 +40,6 @@ export default { } }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/packages/unminify/src/transforms/index.ts b/packages/unminify/src/transforms/index.ts new file mode 100644 index 00000000..2713ab43 --- /dev/null +++ b/packages/unminify/src/transforms/index.ts @@ -0,0 +1,14 @@ +export { default as blockStatements } from "./block-statements"; +export { default as computedProperties } from "./computed-properties"; +export { default as jsonParse } from "./json-parse"; +export { default as logicalToIf } from "./logical-to-if"; +export { default as mergeElseIf } from "./merge-else-if"; +export { default as mergeStrings } from "./merge-strings"; +export { default as numberExpressions } from "./number-expressions"; +export { default as rawLiterals } from "./raw-literals"; +export { default as sequence } from "./sequence"; +export { default as splitVariableDeclarations } from "./split-variable-declarations"; +export { default as ternaryToIf } from "./ternary-to-if"; +export { default as unminifyBooleans } from "./unminify-booleans"; +export { default as voidToUndefined } from "./void-to-undefined"; +export { default as yoda } from "./yoda"; diff --git a/src/transforms/jsonParse.ts b/packages/unminify/src/transforms/json-parse.ts similarity index 57% rename from src/transforms/jsonParse.ts rename to packages/unminify/src/transforms/json-parse.ts index a4d02156..6b28127f 100644 --- a/src/transforms/jsonParse.ts +++ b/packages/unminify/src/transforms/json-parse.ts @@ -1,21 +1,21 @@ -import { parseExpression } from '@babel/parser'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; -import { constMemberExpression } from '../utils/matcher'; +import { parseExpression } from "@babel/parser"; +import * as m from "@codemod/matchers"; +import { Transform, constMemberExpression } from "@webcrack/ast-utils"; export default { - name: 'jsonParse', - tags: ['safe'], + name: "json-parse", + tags: ["safe"], + scope: true, visitor: () => { const string = m.capture(m.anyString()); - const matcher = m.callExpression(constMemberExpression('JSON', 'parse'), [ + const matcher = m.callExpression(constMemberExpression("JSON", "parse"), [ m.stringLiteral(string), ]); return { CallExpression: { exit(path) { - if (matcher.match(path.node)) { + if (matcher.match(path.node) && !path.scope.hasBinding("JSON")) { try { JSON.parse(string.current!); const parsed = parseExpression(string.current!); @@ -27,7 +27,6 @@ export default { } }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/src/transforms/booleanIf.ts b/packages/unminify/src/transforms/logical-to-if.ts similarity index 77% rename from src/transforms/booleanIf.ts rename to packages/unminify/src/transforms/logical-to-if.ts index f5123388..777c628a 100644 --- a/src/transforms/booleanIf.ts +++ b/packages/unminify/src/transforms/logical-to-if.ts @@ -1,14 +1,14 @@ -import { statement } from '@babel/template'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import { statement } from "@babel/template"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'booleanIf', - tags: ['safe'], + name: "logical-to-if", + tags: ["safe"], visitor: () => { - const andMatcher = m.expressionStatement(m.logicalExpression('&&')); - const orMatcher = m.expressionStatement(m.logicalExpression('||')); + const andMatcher = m.expressionStatement(m.logicalExpression("&&")); + const orMatcher = m.expressionStatement(m.logicalExpression("||")); const buildIf = statement`if (TEST) { BODY; }`; const buildIfNot = statement`if (!TEST) { BODY; }`; @@ -22,7 +22,7 @@ export default { buildIf({ TEST: expression.left, BODY: expression.right, - }) + }), ); this.changes++; } else if (orMatcher.match(path.node)) { @@ -30,13 +30,12 @@ export default { buildIfNot({ TEST: expression.left, BODY: expression.right, - }) + }), ); this.changes++; } }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/packages/unminify/src/transforms/merge-else-if.ts b/packages/unminify/src/transforms/merge-else-if.ts new file mode 100644 index 00000000..f3f41385 --- /dev/null +++ b/packages/unminify/src/transforms/merge-else-if.ts @@ -0,0 +1,26 @@ +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; + +export default { + name: "merge-else-if", + tags: ["safe"], + visitor() { + const nestedIf = m.capture(m.ifStatement()); + const matcher = m.ifStatement( + m.anything(), + m.anything(), + m.blockStatement([nestedIf]), + ); + + return { + IfStatement: { + exit(path) { + if (matcher.match(path.node)) { + path.node.alternate = nestedIf.current; + this.changes++; + } + }, + }, + }; + }, +} satisfies Transform; diff --git a/src/transforms/mergeStrings.ts b/packages/unminify/src/transforms/merge-strings.ts similarity index 73% rename from src/transforms/mergeStrings.ts rename to packages/unminify/src/transforms/merge-strings.ts index 6f508ff7..a5318ed2 100644 --- a/src/transforms/mergeStrings.ts +++ b/packages/unminify/src/transforms/merge-strings.ts @@ -1,19 +1,19 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'mergeStrings', - tags: ['safe'], + name: "merge-strings", + tags: ["safe"], visitor() { const left = m.capture(m.stringLiteral(m.anyString())); const right = m.capture(m.stringLiteral(m.anyString())); - const matcher = m.binaryExpression('+', left, right); + const matcher = m.binaryExpression("+", left, right); const nestedMatcher = m.binaryExpression( - '+', - m.binaryExpression('+', m.anything(), left), - right + "+", + m.binaryExpression("+", m.anything(), left), + right, ); return { @@ -22,7 +22,7 @@ export default { if (matcher.match(path.node)) { // "a" + "b" -> "ab" path.replaceWith( - t.stringLiteral(left.current!.value + right.current!.value) + t.stringLiteral(left.current!.value + right.current!.value), ); this.changes++; } @@ -39,8 +39,6 @@ export default { } }, }, - - noScope: true, }; }, } satisfies Transform; diff --git a/src/transforms/numberExpressions.ts b/packages/unminify/src/transforms/number-expressions.ts similarity index 53% rename from src/transforms/numberExpressions.ts rename to packages/unminify/src/transforms/number-expressions.ts index 55412de5..89924d8a 100644 --- a/src/transforms/numberExpressions.ts +++ b/packages/unminify/src/transforms/number-expressions.ts @@ -1,12 +1,12 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'numberExpressions', - tags: ['safe'], + name: "number-expressions", + tags: ["safe"], visitor: () => ({ - 'BinaryExpression|UnaryExpression': { + "BinaryExpression|UnaryExpression": { exit(path) { if (matcher.match(path.node)) { const evaluated = path.evaluate(); @@ -18,33 +18,32 @@ export default { } }, }, - noScope: true, }), } satisfies Transform; const matcher: m.Matcher = m.or( m.binaryExpression( - m.or('+', '-', '*'), - m.matcher(node => matcher.match(node)), - m.matcher(node => matcher.match(node)) + m.or("+", "-", "*"), + m.matcher((node) => matcher.match(node)), + m.matcher((node) => matcher.match(node)), ), m.binaryExpression( - '-', + "-", m.or( m.stringLiteral(), - m.matcher(node => matcher.match(node)) + m.matcher((node) => matcher.match(node)), ), m.or( m.stringLiteral(), - m.matcher(node => matcher.match(node)) - ) + m.matcher((node) => matcher.match(node)), + ), ), m.unaryExpression( - '-', + "-", m.or( m.stringLiteral(), - m.matcher(node => matcher.match(node)) - ) + m.matcher((node) => matcher.match(node)), + ), ), - m.numericLiteral() + m.numericLiteral(), ); diff --git a/src/transforms/rawLiterals.ts b/packages/unminify/src/transforms/raw-literals.ts similarity index 78% rename from src/transforms/rawLiterals.ts rename to packages/unminify/src/transforms/raw-literals.ts index 39a8ad25..877d66ca 100644 --- a/src/transforms/rawLiterals.ts +++ b/packages/unminify/src/transforms/raw-literals.ts @@ -1,8 +1,8 @@ -import { Transform } from '.'; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'rawLiterals', - tags: ['safe'], + name: "raw-literals", + tags: ["safe"], visitor: () => ({ StringLiteral(path) { if (path.node.extra) { @@ -16,6 +16,5 @@ export default { this.changes++; } }, - noScope: true, }), } satisfies Transform; diff --git a/src/transforms/sequence.ts b/packages/unminify/src/transforms/sequence.ts similarity index 72% rename from src/transforms/sequence.ts rename to packages/unminify/src/transforms/sequence.ts index 6e62dfa8..036cc345 100644 --- a/src/transforms/sequence.ts +++ b/packages/unminify/src/transforms/sequence.ts @@ -1,16 +1,16 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'sequence', - tags: ['safe'], + name: "sequence", + tags: ["safe"], visitor: () => ({ ExpressionStatement: { exit(path) { if (t.isSequenceExpression(path.node.expression)) { - const statements = path.node.expression.expressions.map(expr => - t.expressionStatement(expr) + const statements = path.node.expression.expressions.map((expr) => + t.expressionStatement(expr), ); path.replaceWithMultiple(statements); this.changes++; @@ -22,18 +22,18 @@ export default { if (t.isSequenceExpression(path.node.argument)) { const expressions = path.node.argument.expressions; path.node.argument = expressions.pop(); - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); this.changes++; } else if ( - t.isUnaryExpression(path.node.argument, { operator: 'void' }) && + t.isUnaryExpression(path.node.argument, { operator: "void" }) && t.isSequenceExpression(path.node.argument.argument) ) { const expressions = path.node.argument.argument.expressions; - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); path.node.argument = null; @@ -46,8 +46,8 @@ export default { if (t.isSequenceExpression(path.node.test)) { const expressions = path.node.test.expressions; path.node.test = expressions.pop()!; - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); this.changes++; @@ -59,8 +59,8 @@ export default { if (t.isSequenceExpression(path.node.discriminant)) { const expressions = path.node.discriminant.expressions; path.node.discriminant = expressions.pop()!; - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); this.changes++; @@ -72,8 +72,8 @@ export default { if (t.isSequenceExpression(path.node.argument)) { const expressions = path.node.argument.expressions; path.node.argument = expressions.pop()!; - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); this.changes++; @@ -87,8 +87,8 @@ export default { if (matcher.match(path.node)) { const expressions = sequence.current!.expressions; path.node.right = expressions.pop()!; - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); this.changes++; @@ -98,8 +98,8 @@ export default { ForStatement: { exit(path) { if (t.isSequenceExpression(path.node.init)) { - const statements = path.node.init.expressions.map(expr => - t.expressionStatement(expr) + const statements = path.node.init.expressions.map((expr) => + t.expressionStatement(expr), ); path.insertBefore(statements); path.node.init = null; @@ -107,12 +107,12 @@ export default { } if ( t.isSequenceExpression(path.node.update) && - path.node.body.type === 'EmptyStatement' + path.node.body.type === "EmptyStatement" ) { const expressions = path.node.update.expressions; path.node.update = expressions.pop()!; - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); path.node.body = t.blockStatement(statements); this.changes++; @@ -128,10 +128,10 @@ export default { if (matcher.match(path.node)) { const expressions = sequence.current!.expressions; path.node.declarations[0].init = expressions.pop(); - const statements = expressions.map(expr => - t.expressionStatement(expr) + const statements = expressions.map((expr) => + t.expressionStatement(expr), ); - if (path.parentPath.isForStatement() && path.key === 'init') { + if (path.parentPath.isForStatement() && path.key === "init") { path.parentPath.insertBefore(statements); } else { path.insertBefore(statements); @@ -140,6 +140,5 @@ export default { } }, }, - noScope: true, }), } satisfies Transform; diff --git a/src/transforms/splitVariableDeclarations.ts b/packages/unminify/src/transforms/split-variable-declarations.ts similarity index 57% rename from src/transforms/splitVariableDeclarations.ts rename to packages/unminify/src/transforms/split-variable-declarations.ts index 800bbd69..38b80e1c 100644 --- a/src/transforms/splitVariableDeclarations.ts +++ b/packages/unminify/src/transforms/split-variable-declarations.ts @@ -1,32 +1,31 @@ -import * as t from '@babel/types'; -import { Transform } from '.'; +import * as t from "@babel/types"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'splitVariableDeclarations', - tags: ['safe'], + name: "split-variable-declarations", + tags: ["safe"], visitor: () => ({ VariableDeclaration: { exit(path) { - if (path.node.declarations.length > 1 && path.key !== 'init') { + if (path.node.declarations.length > 1 && path.key !== "init") { if (path.parentPath.isExportNamedDeclaration()) { path.parentPath.replaceWithMultiple( - path.node.declarations.map(declaration => + path.node.declarations.map((declaration) => t.exportNamedDeclaration( - t.variableDeclaration(path.node.kind, [declaration]) - ) - ) + t.variableDeclaration(path.node.kind, [declaration]), + ), + ), ); } else { path.replaceWithMultiple( - path.node.declarations.map(declaration => - t.variableDeclaration(path.node.kind, [declaration]) - ) + path.node.declarations.map((declaration) => + t.variableDeclaration(path.node.kind, [declaration]), + ), ); } this.changes++; } }, }, - noScope: true, }), } satisfies Transform; diff --git a/src/transforms/ternaryToIf.ts b/packages/unminify/src/transforms/ternary-to-if.ts similarity index 85% rename from src/transforms/ternaryToIf.ts rename to packages/unminify/src/transforms/ternary-to-if.ts index 78523be6..cf41ba77 100644 --- a/src/transforms/ternaryToIf.ts +++ b/packages/unminify/src/transforms/ternary-to-if.ts @@ -1,10 +1,10 @@ -import { statement } from '@babel/template'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import { statement } from "@babel/template"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; export default { - name: 'ternaryToIf', - tags: ['safe'], + name: "ternary-to-if", + tags: ["safe"], visitor() { const test = m.capture(m.anyExpression()); const consequent = m.capture(m.anyExpression()); @@ -23,7 +23,7 @@ export default { TEST: test.current, CONSEQUENT: consequent.current, ALTERNATE: alternate.current, - }) + }), ); this.changes++; } @@ -37,13 +37,12 @@ export default { TEST: test.current, CONSEQUENT: consequent.current, ALTERNATE: alternate.current, - }) + }), ); this.changes++; } }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/packages/unminify/src/transforms/unminify-booleans.ts b/packages/unminify/src/transforms/unminify-booleans.ts new file mode 100644 index 00000000..8b5700a8 --- /dev/null +++ b/packages/unminify/src/transforms/unminify-booleans.ts @@ -0,0 +1,30 @@ +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; + +export default { + name: "unminify-booleans", + tags: ["safe"], + visitor: () => ({ + UnaryExpression(path) { + if (trueMatcher.match(path.node)) { + path.replaceWith(t.booleanLiteral(true)); + this.changes++; + } else if (falseMatcher.match(path.node)) { + path.replaceWith(t.booleanLiteral(false)); + this.changes++; + } + }, + }), +} satisfies Transform; + +const trueMatcher = m.or( + m.unaryExpression("!", m.numericLiteral(0)), + m.unaryExpression("!", m.unaryExpression("!", m.numericLiteral(1))), + m.unaryExpression("!", m.unaryExpression("!", m.arrayExpression([]))), +); + +const falseMatcher = m.or( + m.unaryExpression("!", m.numericLiteral(1)), + m.unaryExpression("!", m.arrayExpression([])), +); diff --git a/packages/unminify/src/transforms/void-to-undefined.ts b/packages/unminify/src/transforms/void-to-undefined.ts new file mode 100644 index 00000000..ef9b20c7 --- /dev/null +++ b/packages/unminify/src/transforms/void-to-undefined.ts @@ -0,0 +1,25 @@ +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; + +export default { + name: "void-to-undefined", + tags: ["safe"], + scope: true, + visitor: () => { + const matcher = m.unaryExpression("void", m.numericLiteral(0)); + return { + UnaryExpression: { + exit(path) { + if ( + matcher.match(path.node) && + !path.scope.hasBinding("undefined", { noGlobals: true }) + ) { + path.replaceWith(t.identifier("undefined")); + this.changes++; + } + }, + }, + }; + }, +} satisfies Transform; diff --git a/src/transforms/yoda.ts b/packages/unminify/src/transforms/yoda.ts similarity index 60% rename from src/transforms/yoda.ts rename to packages/unminify/src/transforms/yoda.ts index b277cf67..a5eb94f3 100644 --- a/src/transforms/yoda.ts +++ b/packages/unminify/src/transforms/yoda.ts @@ -1,41 +1,41 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; // https://eslint.org/docs/latest/rules/yoda and https://babeljs.io/docs/en/babel-plugin-minify-flip-comparisons const flippedOperators = { - '==': '==', - '===': '===', - '!=': '!=', - '!==': '!==', - '>': '<', - '<': '>', - '>=': '<=', - '<=': '>=', - '*': '*', - '^': '^', - '&': '&', - '|': '|', + "==": "==", + "===": "===", + "!=": "!=", + "!==": "!==", + ">": "<", + "<": ">", + ">=": "<=", + "<=": ">=", + "*": "*", + "^": "^", + "&": "&", + "|": "|", } as const; export default { - name: 'yoda', - tags: ['safe'], + name: "yoda", + tags: ["safe"], visitor: () => { const matcher = m.binaryExpression( m.or(...Object.values(flippedOperators)), m.or( m.stringLiteral(), m.numericLiteral(), - m.unaryExpression('-', m.numericLiteral()), + m.unaryExpression("-", m.numericLiteral()), m.booleanLiteral(), m.nullLiteral(), - m.identifier('undefined'), - m.identifier('NaN'), - m.identifier('Infinity') + m.identifier("undefined"), + m.identifier("NaN"), + m.identifier("Infinity"), ), - m.matcher(node => !t.isLiteral(node)) + m.matcher((node) => !t.isLiteral(node)), ); return { @@ -49,7 +49,6 @@ export default { } }, }, - noScope: true, }; }, } satisfies Transform; diff --git a/packages/unminify/test/block-statements.test.ts b/packages/unminify/test/block-statements.test.ts new file mode 100644 index 00000000..ec24fb3a --- /dev/null +++ b/packages/unminify/test/block-statements.test.ts @@ -0,0 +1,66 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { blockStatements } from "../src/transforms"; + +const expectJS = testTransform(blockStatements); + +test("if statement", () => + expectJS(` + if (a) b(); + `).toMatchInlineSnapshot(` + if (a) { + b(); + } + `)); + +test("while statement", () => + expectJS(` + while (a) b(); + `).toMatchInlineSnapshot(` + while (a) { + b(); + } + `)); + +test("for statement", () => + expectJS(` + for (;;) b(); + `).toMatchInlineSnapshot(` + for (;;) { + b(); + } + `)); + +test("for-in statement", () => + expectJS(` + for (const key in object) b(); + `).toMatchInlineSnapshot(` + for (const key in object) { + b(); + } + `)); + +test("for-of statement", () => + expectJS(` + for (const item of array) b(); + `).toMatchInlineSnapshot(` + for (const item of array) { + b(); + } + `)); + +test("arrow function", () => + expectJS(` + const x = () => (a(), b()); + `).toMatchInlineSnapshot(` + const x = () => { + return a(), b(); + }; + `)); + +test("ignore empty statement", () => + expectJS(` + while (arr.pop()); + `).toMatchInlineSnapshot(` + while (arr.pop()); + `)); diff --git a/packages/unminify/test/computed-properties.test.ts b/packages/unminify/test/computed-properties.test.ts new file mode 100644 index 00000000..c6f1d482 --- /dev/null +++ b/packages/unminify/test/computed-properties.test.ts @@ -0,0 +1,41 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { computedProperties } from "../src/transforms"; + +const expectJS = testTransform(computedProperties); + +test("member expression", () => { + expectJS(` + require("foo")["default"]?.["_"]; + `).toMatchInlineSnapshot('require("foo").default?._;'); +}); + +test("object", () => { + expectJS(` + const x = { ["foo"](){}, ["bar"]: 1 }; + `).toMatchInlineSnapshot(` + const x = { + foo() {}, + bar: 1 + }; + `); +}); + +test("class", () => { + expectJS(` + class Foo { + ["foo"](){} + ["bar"] = 1; + } + `).toMatchInlineSnapshot(` + class Foo { + foo() {} + bar = 1; + } + `); +}); + +test("ignore invalid identifier", () => + expectJS(` + console["1"]("hello"); + `).toMatchInlineSnapshot('console["1"]("hello");')); diff --git a/packages/unminify/test/index.ts b/packages/unminify/test/index.ts new file mode 100644 index 00000000..38479fab --- /dev/null +++ b/packages/unminify/test/index.ts @@ -0,0 +1,14 @@ +import { parse } from "@babel/parser"; +import { Transform, applyTransform } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +export function testTransform(transform: Transform) { + return (input: string, options?: Options) => { + const ast = parse(input, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + }); + applyTransform(ast, transform, options); + return expect(ast); + }; +} diff --git a/packages/unminify/test/json-parse.test.ts b/packages/unminify/test/json-parse.test.ts new file mode 100644 index 00000000..49a45695 --- /dev/null +++ b/packages/unminify/test/json-parse.test.ts @@ -0,0 +1,24 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { jsonParse } from "../src/transforms"; + +const expectJS = testTransform(jsonParse); + +test("array", () => + expectJS('JSON.parse("[1,2,3]")').toMatchInlineSnapshot('JSON.parse("[1,2,3]");')); + +test("large literal", () => + expectJS('JSON.parse("1000000000000000000000")').toMatchInlineSnapshot( + 'JSON.parse("1000000000000000000000");', + )); + +test("ignore invalid json", () => + expectJS('JSON.parse("abc")').toMatchInlineSnapshot('JSON.parse("abc");')); + +test("ignore when JSON is declared in scope", () => + expectJS('let JSON; JSON.parse("null")').toMatchInlineSnapshot( + ` + let JSON; + JSON.parse("null"); + `, + )); diff --git a/packages/unminify/test/logical-to-if.test.ts b/packages/unminify/test/logical-to-if.test.ts new file mode 100644 index 00000000..04b5ac5e --- /dev/null +++ b/packages/unminify/test/logical-to-if.test.ts @@ -0,0 +1,23 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { logicalToIf } from "../src/transforms"; + +const expectJS = testTransform(logicalToIf); + +test("and", () => + expectJS(` + x && y && z(); + `).toMatchInlineSnapshot(` + if (x && y) { + z(); + } + `)); + +test("or", () => + expectJS(` + x || y || z(); + `).toMatchInlineSnapshot(` + if (!(x || y)) { + z(); + } + `)); diff --git a/packages/unminify/test/merge-else-if.test.ts b/packages/unminify/test/merge-else-if.test.ts new file mode 100644 index 00000000..8c2c75cc --- /dev/null +++ b/packages/unminify/test/merge-else-if.test.ts @@ -0,0 +1,25 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { mergeElseIf } from "../src/transforms"; + +const expectJS = testTransform(mergeElseIf); + +test("merge", () => + expectJS(` + if (x) { + } else { + if (y) {} + }`).toMatchInlineSnapshot("if (x) {} else if (y) {}")); + +test("ignore when it contains other statements", () => + expectJS(` + if (x) { + } else { + if (y) {} + z(); + }`).toMatchInlineSnapshot(` + if (x) {} else { + if (y) {} + z(); + } + `)); diff --git a/packages/unminify/test/merge-strings.test.ts b/packages/unminify/test/merge-strings.test.ts new file mode 100644 index 00000000..0fb7cc2f --- /dev/null +++ b/packages/unminify/test/merge-strings.test.ts @@ -0,0 +1,15 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { mergeStrings } from "../src/transforms"; + +const expectJS = testTransform(mergeStrings); + +test("only strings", () => + expectJS(` + "a" + "b" + "c"; + `).toMatchInlineSnapshot('"abc";')); + +test("with variables", () => + expectJS(` + "a" + "b" + xyz + "c" + "d"; + `).toMatchInlineSnapshot('"ab" + xyz + "cd";')); diff --git a/packages/unminify/test/number-expressions.test.ts b/packages/unminify/test/number-expressions.test.ts new file mode 100644 index 00000000..2d851333 --- /dev/null +++ b/packages/unminify/test/number-expressions.test.ts @@ -0,0 +1,25 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { numberExpressions } from "../src/transforms"; + +const expectJS = testTransform(numberExpressions); + +test("simplify", () => + expectJS(` + console.log(-0x1021e + -0x7eac8 + 0x17 * 0xac9c); + `).toMatchInlineSnapshot("console.log(431390);")); + +test("simplify coerced strings", () => + expectJS(` + console.log(-"0xa6" - -331, -"0xa6"); + `).toMatchInlineSnapshot("console.log(165, -166);")); + +test("ignore string results", () => + expectJS(` + console.log(0x1021e + "test"); + `).toMatchInlineSnapshot('console.log(0x1021e + "test");')); + +test("keep divisions", () => + expectJS(` + console.log((-0x152f + 0x1281 * -0x1 + -0x18 * -0x1d1) / (0x83 * -0x1a + -0x19ea + 0x5f * 0x6a)); + `).toMatchInlineSnapshot("console.log(1000 / 30);")); diff --git a/packages/unminify/test/raw-literals.test.ts b/packages/unminify/test/raw-literals.test.ts new file mode 100644 index 00000000..45eb6843 --- /dev/null +++ b/packages/unminify/test/raw-literals.test.ts @@ -0,0 +1,13 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { rawLiterals } from "../src/transforms"; + +const expectJS = testTransform(rawLiterals); + +test("string", () => + expectJS( + String.raw`f("\x61", '"', "\u270F\uFE0F", "\u2028\u2029\t")`, + ).toMatchInlineSnapshot('f("a", "\\"", "✏️", "\\u2028\\u2029\\t");')); + +test("number", () => + expectJS("const a = 0x1;").toMatchInlineSnapshot("const a = 1;")); diff --git a/packages/unminify/test/sequence.test.ts b/packages/unminify/test/sequence.test.ts new file mode 100644 index 00000000..5e8a226f --- /dev/null +++ b/packages/unminify/test/sequence.test.ts @@ -0,0 +1,104 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { sequence } from "../src/transforms"; + +const expectJS = testTransform(sequence); + +test("to statements", () => + expectJS(` + if (a) b(), c(); + `).toMatchInlineSnapshot(` + if (a) { + b(); + c(); + } + `)); + +test("rearrange from return", () => + expectJS(` + function f() { + return a(), b(), c(); + } + `).toMatchInlineSnapshot(` + function f() { + a(); + b(); + return c(); + } + `)); + +test("return void", () => + expectJS(` + return void (a(), b()); + `).toMatchInlineSnapshot(` + a(); + b(); + return; + `)); + +test("rearrange from if", () => + expectJS(` + if (a(), b()) c(); + `).toMatchInlineSnapshot(` + a(); + if (b()) c(); + `)); + +test("rearrange from switch", () => + expectJS(` + switch (a(), b()) {} + `).toMatchInlineSnapshot(` + a(); + switch (b()) {} + `)); + +test("throw", () => + expectJS(` + throw a(), b(); + `).toMatchInlineSnapshot(` + a(); + throw b(); + `)); + +test("rearrange from for-in", () => + expectJS(` + for (let key in a = 1, object) {} + `).toMatchInlineSnapshot(` + a = 1; + for (let key in object) {} + `)); + +test("rearrange from for loop init", () => + expectJS(` + for((a(), b());;); + `).toMatchInlineSnapshot(` + a(); + b(); + for (;;); + `)); + +test("rearrange from for loop update", () => + expectJS(` + for(; i < 10; a(), b(), i++); + `).toMatchInlineSnapshot(` + for (; i < 10; i++) { + a(); + b(); + } + `)); + +test("rearrange variable declarator", () => + expectJS(` + var t = (o = null, o); + `).toMatchInlineSnapshot(` + o = null; + var t = o; + `)); + +test("dont rearrange variable declarator in for loop", () => + expectJS(` + for(let a = (b, c);;) {} + `).toMatchInlineSnapshot(` + b; + for (let a = c;;) {} + `)); diff --git a/packages/unminify/test/setup.ts b/packages/unminify/test/setup.ts new file mode 100644 index 00000000..f50b672e --- /dev/null +++ b/packages/unminify/test/setup.ts @@ -0,0 +1,8 @@ +import * as t from "@babel/types"; +import { generate } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +expect.addSnapshotSerializer({ + test: (val: unknown) => t.isNode(val) && !("parentPath" in val), + serialize: (val: t.Node) => generate(val), +}); diff --git a/packages/unminify/test/split-variable-declarations.test.ts b/packages/unminify/test/split-variable-declarations.test.ts new file mode 100644 index 00000000..751497a5 --- /dev/null +++ b/packages/unminify/test/split-variable-declarations.test.ts @@ -0,0 +1,33 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { splitVariableDeclarations } from "../src/transforms"; + +const expectJS = testTransform(splitVariableDeclarations); + +test("split variable declarations", () => + expectJS(` + const a = 1, b = 2, c = 3; + `).toMatchInlineSnapshot(` + const a = 1; + const b = 2; + const c = 3; + `)); + +test("split exported variable declarations", () => + expectJS(` + export const a = 1, b = 2, c = 3; + `).toMatchInlineSnapshot(` + export const a = 1; + export const b = 2; + export const c = 3; + `)); + +test("dont split in for loop", () => + expectJS(` + for (let i = 0, j = 1; i < 10; i++, j++) var a, b; + `).toMatchInlineSnapshot(` + for (let i = 0, j = 1; i < 10; i++, j++) { + var a; + var b; + } + `)); diff --git a/packages/unminify/test/ternary-to-if.test.ts b/packages/unminify/test/ternary-to-if.test.ts new file mode 100644 index 00000000..23bb483e --- /dev/null +++ b/packages/unminify/test/ternary-to-if.test.ts @@ -0,0 +1,32 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { ternaryToIf } from "../src/transforms"; + +const expectJS = testTransform(ternaryToIf); + +test("statement", () => + expectJS(` + a ? b() : c(); + `).toMatchInlineSnapshot(` + if (a) { + b(); + } else { + c(); + } + `)); + +test("returned", () => + expectJS(` + return a ? b() : c(); + `).toMatchInlineSnapshot(` + if (a) { + return b(); + } else { + return c(); + } + `)); + +test("ignore expression", () => + expectJS(` + const x = a ? b() : c(); + `).toMatchInlineSnapshot("const x = a ? b() : c();")); diff --git a/packages/unminify/test/unminify-booleans.test.ts b/packages/unminify/test/unminify-booleans.test.ts new file mode 100644 index 00000000..455ef0b6 --- /dev/null +++ b/packages/unminify/test/unminify-booleans.test.ts @@ -0,0 +1,16 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { unminifyBooleans } from "../src/transforms"; + +const expectJS = testTransform(unminifyBooleans); + +test("true", () => { + expectJS("!0").toMatchInlineSnapshot("true;"); + expectJS("!!1").toMatchInlineSnapshot("true;"); + expectJS("!![]").toMatchInlineSnapshot("true;"); +}); + +test("false", () => { + expectJS("!1").toMatchInlineSnapshot("false;"); + expectJS("![]").toMatchInlineSnapshot("false;"); +}); diff --git a/packages/unminify/test/void-to-undefined.test.ts b/packages/unminify/test/void-to-undefined.test.ts new file mode 100644 index 00000000..d96163e0 --- /dev/null +++ b/packages/unminify/test/void-to-undefined.test.ts @@ -0,0 +1,15 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { voidToUndefined } from "../src/transforms"; + +const expectJS = testTransform(voidToUndefined); + +test("void 0", () => expectJS("void 0").toMatchInlineSnapshot("undefined;")); + +test("ignore when undefined is declared in scope", () => + expectJS("let undefined = 1; { void 0; }").toMatchInlineSnapshot(` + let undefined = 1; + { + void 0; + } + `)); diff --git a/packages/unminify/test/yoda.test.ts b/packages/unminify/test/yoda.test.ts new file mode 100644 index 00000000..ecdcb323 --- /dev/null +++ b/packages/unminify/test/yoda.test.ts @@ -0,0 +1,62 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { yoda } from "../src/transforms"; + +const expectJS = testTransform(yoda); + +test("strict equality", () => + expectJS('"red" === color').toMatchInlineSnapshot('color === "red";')); + +test("loose equality", () => + expectJS("null == x").toMatchInlineSnapshot("x == null;")); + +test("strict inequality", () => + expectJS('"red" !== color').toMatchInlineSnapshot('color !== "red";')); + +test("loose inequality", () => + expectJS("null != x").toMatchInlineSnapshot("x != null;")); + +test("less than", () => expectJS("0 < x").toMatchInlineSnapshot("x > 0;")); + +test("less or equal", () => + expectJS("0 <= x").toMatchInlineSnapshot("x >= 0;")); + +test("greater than", () => expectJS("0 > x").toMatchInlineSnapshot("x < 0;")); + +test("greater or equal", () => + expectJS("0 >= x").toMatchInlineSnapshot("x <= 0;")); + +test("multiply", () => expectJS("0 * x").toMatchInlineSnapshot("x * 0;")); + +test("xor", () => expectJS("0 ^ x").toMatchInlineSnapshot("x ^ 0;")); + +test("and", () => expectJS("0 & x").toMatchInlineSnapshot("x & 0;")); + +test("or", () => expectJS("0 | x").toMatchInlineSnapshot("x | 0;")); + +test("string", () => + expectJS('"str" == x').toMatchInlineSnapshot('x == "str";')); + +test("number", () => expectJS("1 == x").toMatchInlineSnapshot("x == 1;")); + +test("negative number", () => + expectJS("-1 == x").toMatchInlineSnapshot("x == -1;")); + +test("boolean", () => + expectJS("true == x").toMatchInlineSnapshot("x == true;")); + +test("null", () => expectJS("null == x").toMatchInlineSnapshot("x == null;")); + +test("undefined", () => + expectJS("undefined == x").toMatchInlineSnapshot("x == undefined;")); + +test("NaN", () => expectJS("NaN == x").toMatchInlineSnapshot("x == NaN;")); + +test("Infinity", () => + expectJS("Infinity == x").toMatchInlineSnapshot("x == Infinity;")); + +test("ignore other operators", () => + expectJS("2 + x").toMatchInlineSnapshot("2 + x;")); + +test("ignore when right side is a literal", () => + expectJS("1 === 2").toMatchInlineSnapshot("1 === 2;")); diff --git a/packages/unminify/tsconfig.json b/packages/unminify/tsconfig.json new file mode 100644 index 00000000..fca8f92b --- /dev/null +++ b/packages/unminify/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@webcrack/typescript-config/base.json", +} diff --git a/packages/unminify/vitest.config.ts b/packages/unminify/vitest.config.ts new file mode 100644 index 00000000..cd893d71 --- /dev/null +++ b/packages/unminify/vitest.config.ts @@ -0,0 +1,11 @@ +import { join } from "node:path"; +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + root: join(__dirname, "test"), + setupFiles: "setup.ts", + include: ["**/*.test.ts"], + isolate: false, + }, +}); diff --git a/packages/unpack/.eslintrc.cjs b/packages/unpack/.eslintrc.cjs new file mode 100644 index 00000000..d0f2c30e --- /dev/null +++ b/packages/unpack/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], +}; diff --git a/packages/unpack/package.json b/packages/unpack/package.json new file mode 100644 index 00000000..82929c31 --- /dev/null +++ b/packages/unpack/package.json @@ -0,0 +1,29 @@ +{ + "name": "@webcrack/unpack", + "version": "1.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "lint": "eslint src test", + "lint:fix": "eslint src test --fix", + "test": "vitest" + }, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "@codemod/matchers": "^1.7.0", + "@webcrack/ast-utils": "workspace:*" + }, + "devDependencies": { + "@types/babel__generator": "^7.6.7", + "@types/babel__helper-validator-identifier": "^7.15.2", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.20.4", + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "typescript": "^5.3.2" + } +} diff --git a/src/extractor/browserify/bundle.ts b/packages/unpack/src/browserify/bundle.ts similarity index 50% rename from src/extractor/browserify/bundle.ts rename to packages/unpack/src/browserify/bundle.ts index 916572b7..8429d0ca 100644 --- a/src/extractor/browserify/bundle.ts +++ b/packages/unpack/src/browserify/bundle.ts @@ -1,8 +1,8 @@ -import { Bundle } from '../bundle'; -import { BrowserifyModule } from './module'; +import { Bundle } from "../bundle"; +import { BrowserifyModule } from "./module"; export class BrowserifyBundle extends Bundle { constructor(entryId: string, modules: Map) { - super('browserify', entryId, modules); + super("browserify", entryId, modules); } } diff --git a/src/extractor/browserify/index.ts b/packages/unpack/src/browserify/index.ts similarity index 74% rename from src/extractor/browserify/index.ts rename to packages/unpack/src/browserify/index.ts index 21994758..e22e8311 100644 --- a/src/extractor/browserify/index.ts +++ b/packages/unpack/src/browserify/index.ts @@ -1,18 +1,22 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../../transforms'; -import { getPropName } from '../../utils/ast'; -import { constKey, matchIife } from '../../utils/matcher'; -import { resolveDependencyTree } from '../../utils/path'; -import { renameParameters } from '../../utils/rename'; -import { Bundle } from '../bundle'; -import { BrowserifyBundle } from './bundle'; -import { BrowserifyModule } from './module'; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + Transform, + constKey, + getPropName, + matchIife, + renameParameters, +} from "@webcrack/ast-utils"; +import { Bundle } from "../bundle"; +import { resolveDependencyTree } from "../path"; +import { BrowserifyBundle } from "./bundle"; +import { BrowserifyModule } from "./module"; export const unpackBrowserify = { - name: 'unpack-browserify', - tags: ['unsafe'], + name: "unpack-browserify", + tags: ["unsafe"], + scope: true, visitor(options) { const modules = new Map(); @@ -30,15 +34,15 @@ export const unpackBrowserify = { constKey(), m.or( m.numericLiteral(), - m.identifier('undefined'), - m.stringLiteral() - ) - ) - ) + m.identifier("undefined"), + m.stringLiteral(), + ), + ), + ), ), - ]) - ) - ) + ]), + ), + ), ); const entryIdMatcher = m.capture(m.numericLiteral()); @@ -58,13 +62,13 @@ export const unpackBrowserify = { m.identifier(), ]), m.returnStatement(m.identifier()), - ]) + ]), ), [ m.objectExpression(files), m.objectExpression(), m.arrayExpression([entryIdMatcher]), - ] + ], ); return { @@ -75,7 +79,7 @@ export const unpackBrowserify = { const entryId = entryIdMatcher.current!.value.toString(); const modulesPath = path.get( - files.currentKeys!.join('.') + files.currentKeys!.join("."), ) as NodePath[]; const dependencyTree: Record> = {}; @@ -85,22 +89,22 @@ export const unpackBrowserify = { moduleWrapper.node.key as t.NumericLiteral ).value.toString(); const fn = moduleWrapper.get( - 'value.elements.0' + "value.elements.0", ) as NodePath; const dependencies: Record = (dependencyTree[id] = {}); const dependencyProperties = ( moduleWrapper.get( - 'value.elements.1' + "value.elements.1", ) as NodePath ).node.properties as t.ObjectProperty[]; for (const dependency of dependencyProperties) { // skip external dependencies like { vscode: undefined } if ( - dependency.value.type !== 'NumericLiteral' && - dependency.value.type !== 'StringLiteral' + dependency.value.type !== "NumericLiteral" && + dependency.value.type !== "StringLiteral" ) continue; @@ -109,13 +113,13 @@ export const unpackBrowserify = { dependencies[depId] = filePath; } - renameParameters(fn, ['require', 'module', 'exports']); + renameParameters(fn, ["require", "module", "exports"]); const file = t.file(t.program(fn.node.body.body)); const module = new BrowserifyModule( id, file, id === entryId, - dependencies + dependencies, ); modules.set(id.toString(), module); } @@ -130,7 +134,6 @@ export const unpackBrowserify = { options!.bundle = new BrowserifyBundle(entryId, modules); } }, - noScope: true, }; }, } satisfies Transform<{ bundle: Bundle | undefined }>; diff --git a/src/extractor/browserify/module.ts b/packages/unpack/src/browserify/module.ts similarity index 67% rename from src/extractor/browserify/module.ts rename to packages/unpack/src/browserify/module.ts index e581a00f..3e69dcac 100644 --- a/src/extractor/browserify/module.ts +++ b/packages/unpack/src/browserify/module.ts @@ -1,5 +1,5 @@ -import * as t from '@babel/types'; -import { Module } from '../module'; +import * as t from "@babel/types"; +import { Module } from "../module"; export class BrowserifyModule extends Module { dependencies: Record; @@ -8,7 +8,7 @@ export class BrowserifyModule extends Module { id: string, ast: t.File, isEntry: boolean, - dependencies: Record + dependencies: Record, ) { super(id, ast, isEntry); this.dependencies = dependencies; diff --git a/packages/unpack/src/bundle.ts b/packages/unpack/src/bundle.ts new file mode 100644 index 00000000..ab10e6a8 --- /dev/null +++ b/packages/unpack/src/bundle.ts @@ -0,0 +1,90 @@ +import traverse from "@babel/traverse"; +import * as m from "@codemod/matchers"; +import { posix } from "node:path"; +import { Module } from "./module"; + +// eslint-disable-next-line @typescript-eslint/unbound-method +const { dirname, join, normalize } = posix; + +export class Bundle { + type: "webpack" | "browserify"; + entryId: string; + modules: Map; + + constructor( + type: "webpack" | "browserify", + entryId: string, + modules: Map, + ) { + this.type = type; + this.entryId = entryId; + this.modules = modules; + } + + applyMappings(mappings: Record>): void { + const mappingPaths = Object.keys(mappings); + if (mappingPaths.length === 0) return; + + const unusedMappings = new Set(mappingPaths); + + for (const module of this.modules.values()) { + traverse(module.ast, { + enter(path) { + for (const mappingPath of mappingPaths) { + if (mappings[mappingPath].match(path.node)) { + if (unusedMappings.has(mappingPath)) { + unusedMappings.delete(mappingPath); + } else { + throw new Error(`Mapping ${mappingPath} is already used.`); + } + const resolvedPath = mappingPath.startsWith("./") + ? mappingPath + : `node_modules/${mappingPath}`; + module.path = resolvedPath; + path.stop(); + break; + } + } + }, + noScope: true, + }); + } + } + + /** + * Saves each module to a file and the bundle metadata to a JSON file. + * @param path Output directory + */ + async save(path: string): Promise { + const bundleJson = { + type: this.type, + entryId: this.entryId, + modules: Array.from(this.modules.values(), (module) => ({ + id: module.id, + path: module.path, + })), + }; + + const { mkdir, writeFile } = await import("node:fs/promises"); + await mkdir(path, { recursive: true }); + + await writeFile( + join(path, "bundle.json"), + JSON.stringify(bundleJson, null, 2), + "utf8", + ); + + await Promise.all( + Array.from(this.modules.values(), async (module) => { + const modulePath = normalize(join(path, module.path)); + if (!modulePath.startsWith(path)) { + throw new Error(`detected path traversal: ${module.path}`); + } + await mkdir(dirname(modulePath), { recursive: true }); + await writeFile(modulePath, module.code, "utf8"); + }), + ); + } + + applyTransforms(): void {} +} diff --git a/packages/unpack/src/index.ts b/packages/unpack/src/index.ts new file mode 100644 index 00000000..50e62181 --- /dev/null +++ b/packages/unpack/src/index.ts @@ -0,0 +1,41 @@ +import { parse } from "@babel/parser"; +import traverse, { Visitor, visitors } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { TransformState } from "@webcrack/ast-utils"; +import { unpackBrowserify } from "./browserify"; +import { Bundle } from "./bundle"; +import { unpackWebpack } from "./webpack"; + +export { Bundle } from "./bundle"; + +export function unpack( + code: string, + mappings: Record> = {}, +): Bundle | undefined { + const ast = parse(code, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + plugins: ["jsx"], + }); + return unpackAST(ast, mappings); +} + +export function unpackAST( + ast: t.Node, + mappings: Record> = {}, +): Bundle | undefined { + const options: { bundle: Bundle | undefined } = { bundle: undefined }; + const traverseOptions: Visitor[] = [ + unpackWebpack.visitor(options), + unpackBrowserify.visitor(options), + ]; + const visitor = visitors.merge(traverseOptions); + traverse(ast, visitor, undefined, { changes: 0 }); + // TODO: applyTransforms(ast, [unpackWebpack, unpackBrowserify]) instead + if (options.bundle) { + options.bundle.applyMappings(mappings); + options.bundle.applyTransforms(); + } + return options.bundle; +} diff --git a/packages/unpack/src/matchers.d.ts b/packages/unpack/src/matchers.d.ts new file mode 100644 index 00000000..01526964 --- /dev/null +++ b/packages/unpack/src/matchers.d.ts @@ -0,0 +1,41 @@ +import { Matcher } from "@codemod/matchers"; + +type MatcherType = T extends Matcher ? U : T; + +declare module "@codemod/matchers" { + // The library only implements up to 5 arguments, but we need more + // Also have to keep the other ones because of recursive matchers (numberExpressions.ts) + + export function or(): Matcher; + export function or(first: Matcher | T): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + fifth: Matcher | X, + ): Matcher; + export function or( + ...matchers: T + ): Matcher>; +} + +declare module "@codemod/matchers/build/matchers/predicate" { + // Convenience overload for not having to cast the value when using it + export function predicate(predicate: (value: T) => boolean): Matcher; +} diff --git a/src/extractor/module.ts b/packages/unpack/src/module.ts similarity index 79% rename from src/extractor/module.ts rename to packages/unpack/src/module.ts index 453c3dc0..b0e91bf3 100644 --- a/src/extractor/module.ts +++ b/packages/unpack/src/module.ts @@ -1,5 +1,5 @@ -import * as t from '@babel/types'; -import { generate } from '../utils/generator'; +import * as t from "@babel/types"; +import { generate } from "@webcrack/ast-utils"; export class Module { id: string; @@ -15,7 +15,7 @@ export class Module { this.id = id; this.ast = ast; this.isEntry = isEntry; - this.path = `./${isEntry ? 'index' : id}.js`; + this.path = `./${isEntry ? "index" : id}.js`; } /** diff --git a/src/utils/path.ts b/packages/unpack/src/path.ts similarity index 61% rename from src/utils/path.ts rename to packages/unpack/src/path.ts index a34da0ce..33d1cee2 100644 --- a/src/utils/path.ts +++ b/packages/unpack/src/path.ts @@ -1,10 +1,13 @@ -import assert from 'node:assert'; -import { dirname, join, relative } from 'node:path/posix'; +import assert from "node:assert"; +import { posix } from "node:path"; + +// eslint-disable-next-line @typescript-eslint/unbound-method +const { dirname, join, relative } = posix; export function relativePath(from: string, to: string): string { - if (to.startsWith('node_modules/')) return to.replace('node_modules/', ''); + if (to.startsWith("node_modules/")) return to.replace("node_modules/", ""); const relativePath = relative(dirname(from), to); - return relativePath.startsWith('.') ? relativePath : './' + relativePath; + return relativePath.startsWith(".") ? relativePath : "./" + relativePath; } /** @@ -15,30 +18,30 @@ export function relativePath(from: string, to: string): string { */ export function resolveDependencyTree( tree: Record>, - entry: string + entry: string, ): Record { const paths = resolveTreePaths(tree, entry); - paths[entry] = './index.js'; + paths[entry] = "./index.js"; const entryDepth = Object.values(paths).reduce( - (acc, path) => Math.max(acc, path.split('..').length), - 0 + (acc, path) => Math.max(acc, path.split("..").length), + 0, ); // If the entrypoint is in a subfolder, we need to make up a prefix to get rid of the `../` const prefix = Array(entryDepth - 1) .fill(0) .map((_, i) => `tmp${i}`) - .join('/'); + .join("/"); return Object.fromEntries( Object.entries(paths).map(([id, path]) => { - const newPath = path.startsWith('node_modules/') + const newPath = path.startsWith("node_modules/") ? path : join(prefix, path); - assert(!newPath.includes('..')); - assert(!newPath.startsWith('/')); + assert(!newPath.includes("..")); + assert(!newPath.startsWith("/")); return [id, newPath]; - }) + }), ); } @@ -48,8 +51,8 @@ export function resolveDependencyTree( function resolveTreePaths( graph: Record>, entry: string, - cwd = '.', - paths: Record = {} + cwd = ".", + paths: Record = {}, ) { const entries = Object.entries(graph[entry]); @@ -58,15 +61,15 @@ function resolveTreePaths( if (isCircular) continue; let path: string; - if (name.startsWith('.')) { + if (name.startsWith(".")) { path = join(cwd, name); - if (!path.endsWith('.js')) path += '.js'; + if (!path.endsWith(".js")) path += ".js"; } else { - path = join('node_modules', name, 'index.js'); + path = join("node_modules", name, "index.js"); } paths[id] = path; - const newCwd = path.endsWith('.js') ? dirname(path) : path; + const newCwd = path.endsWith(".js") ? dirname(path) : path; resolveTreePaths(graph, id, newCwd, paths); } diff --git a/src/extractor/webpack/bundle.ts b/packages/unpack/src/webpack/bundle.ts similarity index 63% rename from src/extractor/webpack/bundle.ts rename to packages/unpack/src/webpack/bundle.ts index 4db22bcb..1d10b60b 100644 --- a/src/extractor/webpack/bundle.ts +++ b/packages/unpack/src/webpack/bundle.ts @@ -1,16 +1,16 @@ -import traverse, { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { relativePath } from '../../utils/path'; -import { Bundle } from '../bundle'; -import { convertESM } from './esm'; -import { convertDefaultRequire } from './getDefaultExport'; -import { WebpackModule } from './module'; -import { inlineVarInjections } from './varInjection'; +import traverse, { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Bundle } from "../bundle"; +import { relativePath } from "../path"; +import { convertESM } from "./esm"; +import { convertDefaultRequire } from "./getDefaultExport"; +import { WebpackModule } from "./module"; +import { inlineVarInjections } from "./varInjection"; export class WebpackBundle extends Bundle { constructor(entryId: string, modules: Map) { - super('webpack', entryId, modules); + super("webpack", entryId, modules); } /** @@ -29,23 +29,23 @@ export class WebpackBundle extends Bundle { private replaceRequirePaths() { const requireId = m.capture(m.or(m.numericLiteral(), m.stringLiteral())); const requireMatcher = m.or( - m.callExpression(m.identifier('require'), [requireId]) + m.callExpression(m.identifier("require"), [requireId]), ); const importId = m.capture(m.stringLiteral()); const importMatcher = m.importDeclaration(m.anything(), importId); - this.modules.forEach(module => { + this.modules.forEach((module) => { traverse(module.ast, { - 'CallExpression|ImportDeclaration': path => { + "CallExpression|ImportDeclaration": (path) => { let moduleId: string; let arg: NodePath; if (requireMatcher.match(path.node)) { moduleId = requireId.current!.value.toString(); - [arg] = path.get('arguments') as NodePath[]; + [arg] = path.get("arguments") as NodePath[]; } else if (importMatcher.match(path.node)) { moduleId = importId.current!.value; - arg = path.get('source') as NodePath; + arg = path.get("source") as NodePath; } else { return; } @@ -55,13 +55,13 @@ export class WebpackBundle extends Bundle { t.stringLiteral( relativePath( module.path, - requiredModule?.path ?? `./${moduleId}.js` - ) - ) + requiredModule?.path ?? `./${moduleId}.js`, + ), + ), ); // For example if its stored in another chunk if (!requiredModule) { - arg.addComment('leading', 'webcrack:missing'); + arg.addComment("leading", "webcrack:missing"); } }, noScope: true, diff --git a/src/extractor/webpack/esm.ts b/packages/unpack/src/webpack/esm.ts similarity index 74% rename from src/extractor/webpack/esm.ts rename to packages/unpack/src/webpack/esm.ts index 080f29a8..9c82167f 100644 --- a/src/extractor/webpack/esm.ts +++ b/packages/unpack/src/webpack/esm.ts @@ -1,10 +1,13 @@ -import { statement } from '@babel/template'; -import traverse, { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { constMemberExpression, findPath } from '../../utils/matcher'; -import { renameFast } from '../../utils/rename'; -import { WebpackModule } from './module'; +import { statement } from "@babel/template"; +import traverse, { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + constMemberExpression, + findPath, + renameFast, +} from "@webcrack/ast-utils"; +import { WebpackModule } from "./module"; const buildNamespaceImport = statement`import * as NAME from "PATH";`; const buildNamedExportLet = statement`export let NAME = VALUE;`; @@ -25,7 +28,7 @@ const buildNamedExportLet = statement`export let NAME = VALUE;`; export function convertESM(module: WebpackModule): void { // E.g. require.r(exports); const defineEsModuleMatcher = m.expressionStatement( - m.callExpression(constMemberExpression('require', 'r'), [m.identifier()]) + m.callExpression(constMemberExpression("require", "r"), [m.identifier()]), ); const exportsName = m.capture(m.identifier()); @@ -33,36 +36,36 @@ export function convertESM(module: WebpackModule): void { const returnedValue = m.capture(m.anyExpression()); // E.g. require.d(exports, "counter", function () { return f }); const defineExportMatcher = m.expressionStatement( - m.callExpression(constMemberExpression('require', 'd'), [ + m.callExpression(constMemberExpression("require", "d"), [ exportsName, m.stringLiteral(exportedName), m.functionExpression( undefined, [], - m.blockStatement([m.returnStatement(returnedValue)]) + m.blockStatement([m.returnStatement(returnedValue)]), ), - ]) + ]), ); const emptyObjectVarMatcher = m.variableDeclarator( m.fromCapture(exportsName), - m.objectExpression([]) + m.objectExpression([]), ); const properties = m.capture( m.arrayOf( m.objectProperty( m.identifier(), - m.arrowFunctionExpression([], m.anyExpression()) - ) - ) + m.arrowFunctionExpression([], m.anyExpression()), + ), + ), ); // E.g. require.d(exports, { foo: () => a, bar: () => b }); const defineExportsMatcher = m.expressionStatement( - m.callExpression(constMemberExpression('require', 'd'), [ + m.callExpression(constMemberExpression("require", "d"), [ exportsName, m.objectExpression(properties), - ]) + ]), ); // E.g. const lib = require("./lib.js"); @@ -71,19 +74,19 @@ export function convertESM(module: WebpackModule): void { const requireMatcher = m.variableDeclaration(undefined, [ m.variableDeclarator( requireVariable, - m.callExpression(m.identifier('require'), [ + m.callExpression(m.identifier("require"), [ m.numericLiteral(requiredModuleId), - ]) + ]), ), ]); // module = require.hmd(module); const hmdMatcher = m.expressionStatement( m.assignmentExpression( - '=', - m.identifier('module'), - m.callExpression(constMemberExpression('require', 'hmd')) - ) + "=", + m.identifier("module"), + m.callExpression(constMemberExpression("require", "hmd")), + ), ); traverse(module.ast, { @@ -92,24 +95,24 @@ export function convertESM(module: WebpackModule): void { if (path.parentPath?.parentPath) return path.skip(); if (defineEsModuleMatcher.match(path.node)) { - module.ast.program.sourceType = 'module'; + module.ast.program.sourceType = "module"; path.remove(); } else if ( - module.ast.program.sourceType === 'module' && + module.ast.program.sourceType === "module" && requireMatcher.match(path.node) ) { path.replaceWith( buildNamespaceImport({ NAME: requireVariable.current, PATH: String(requiredModuleId.current), - }) + }), ); } else if (defineExportsMatcher.match(path.node)) { const exportsBinding = path.scope.getBinding(exportsName.current!.name); const emptyObject = emptyObjectVarMatcher.match( - exportsBinding?.path.node + exportsBinding?.path.node, ) - ? (exportsBinding!.path.node.init as t.ObjectExpression) + ? (exportsBinding?.path.node.init as t.ObjectExpression) : null; for (const property of properties.current!) { @@ -118,7 +121,7 @@ export function convertESM(module: WebpackModule): void { .body as t.Expression; if (emptyObject) { emptyObject.properties.push( - t.objectProperty(exportedKey, returnedValue) + t.objectProperty(exportedKey, returnedValue), ); } else { exportVariable(path, returnedValue, exportedKey.name); @@ -139,9 +142,9 @@ export function convertESM(module: WebpackModule): void { function exportVariable( requireDPath: NodePath, value: t.Expression, - exportName: string + exportName: string, ) { - if (value.type === 'Identifier') { + if (value.type === "Identifier") { const binding = requireDPath.scope.getBinding(value.name); if (!binding) return; @@ -150,30 +153,30 @@ function exportVariable( m.or( m.variableDeclaration(), m.classDeclaration(), - m.functionDeclaration() - ) + m.functionDeclaration(), + ), ); if (!declaration) return; - if (exportName === 'default') { + if (exportName === "default") { // `let f = 1;` -> `export default 1;` declaration.replaceWith( t.exportDefaultDeclaration( t.isVariableDeclaration(declaration.node) ? declaration.node.declarations[0].init! - : declaration.node - ) + : declaration.node, + ), ); } else { // `let f = 1;` -> `export let counter = 1;` renameFast(binding, exportName); declaration.replaceWith(t.exportNamedDeclaration(declaration.node)); } - } else if (exportName === 'default') { + } else if (exportName === "default") { requireDPath.insertAfter(t.exportDefaultDeclaration(value)); } else { requireDPath.insertAfter( - buildNamedExportLet({ NAME: t.identifier(exportName), VALUE: value }) + buildNamedExportLet({ NAME: t.identifier(exportName), VALUE: value }), ); } } diff --git a/src/extractor/webpack/getDefaultExport.ts b/packages/unpack/src/webpack/getDefaultExport.ts similarity index 78% rename from src/extractor/webpack/getDefaultExport.ts rename to packages/unpack/src/webpack/getDefaultExport.ts index a3e22538..c0624c40 100644 --- a/src/extractor/webpack/getDefaultExport.ts +++ b/packages/unpack/src/webpack/getDefaultExport.ts @@ -1,8 +1,8 @@ -import { expression } from '@babel/template'; -import traverse, { NodePath } from '@babel/traverse'; -import * as m from '@codemod/matchers'; -import { constMemberExpression } from '../../utils/matcher'; -import { WebpackBundle } from './bundle'; +import { expression } from "@babel/template"; +import traverse, { NodePath } from "@babel/traverse"; +import * as m from "@codemod/matchers"; +import { constMemberExpression } from "@webcrack/ast-utils"; +import { WebpackBundle } from "./bundle"; /* * webpack/runtime/compat get default export @@ -45,7 +45,7 @@ export function convertDefaultRequire(bundle: WebpackBundle): void { // E.g. const m = require(1); const declaratorMatcher = m.variableDeclarator( m.identifier(), - m.callExpression(m.identifier('require'), [requiredModuleId]) + m.callExpression(m.identifier("require"), [requiredModuleId]), ); // E.g. m @@ -53,7 +53,7 @@ export function convertDefaultRequire(bundle: WebpackBundle): void { // E.g. getter const getterVarName = m.capture(m.identifier()); // E.g. require.n(m) - const requireN = m.callExpression(constMemberExpression('require', 'n'), [ + const requireN = m.callExpression(constMemberExpression("require", "n"), [ moduleArg, ]); // E.g. const getter = require.n(m) @@ -61,21 +61,21 @@ export function convertDefaultRequire(bundle: WebpackBundle): void { // E.g. require.n(m).a or require.n(m)() const defaultRequireMatcherAlternative = m.or( - constMemberExpression(requireN, 'a'), - m.callExpression(requireN, []) + constMemberExpression(requireN, "a"), + m.callExpression(requireN, []), ); const buildDefaultAccess = expression`OBJECT.default`; - bundle.modules.forEach(module => { + bundle.modules.forEach((module) => { traverse(module.ast, { - 'CallExpression|MemberExpression'(path) { + "CallExpression|MemberExpression"(path) { if (defaultRequireMatcherAlternative.match(path.node)) { // Replace require.n(m).a or require.n(m)() with m or m.default const requiredModule = getRequiredModule(path); - if (requiredModule?.ast.program.sourceType === 'module') { + if (requiredModule?.ast.program.sourceType === "module") { path.replaceWith( - buildDefaultAccess({ OBJECT: moduleArg.current! }) + buildDefaultAccess({ OBJECT: moduleArg.current! }), ); } else { path.replaceWith(moduleArg.current!); @@ -86,10 +86,10 @@ export function convertDefaultRequire(bundle: WebpackBundle): void { if (defaultRequireMatcher.match(path.node)) { // Replace require.n(m); with m or m.default const requiredModule = getRequiredModule(path); - const init = path.get('init'); - if (requiredModule?.ast.program.sourceType === 'module') { + const init = path.get("init"); + if (requiredModule?.ast.program.sourceType === "module") { init.replaceWith( - buildDefaultAccess({ OBJECT: moduleArg.current! }) + buildDefaultAccess({ OBJECT: moduleArg.current! }), ); } else { init.replaceWith(moduleArg.current!); @@ -97,7 +97,7 @@ export function convertDefaultRequire(bundle: WebpackBundle): void { // Replace getter.a.prop and getter().prop with getter.prop const binding = path.scope.getOwnBinding(getterVarName.current!.name); - binding?.referencePaths.forEach(refPath => { + binding?.referencePaths.forEach((refPath) => { if ( refPath.parentPath?.isCallExpression() || refPath.parentPath?.isMemberExpression() diff --git a/src/extractor/webpack/index.ts b/packages/unpack/src/webpack/index.ts similarity index 67% rename from src/extractor/webpack/index.ts rename to packages/unpack/src/webpack/index.ts index 334b8358..3921b453 100644 --- a/src/extractor/webpack/index.ts +++ b/packages/unpack/src/webpack/index.ts @@ -1,17 +1,21 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '../../transforms'; -import { getPropName } from '../../utils/ast'; -import { constKey, constMemberExpression } from '../../utils/matcher'; -import { renameParameters } from '../../utils/rename'; -import { Bundle } from '../bundle'; -import { WebpackBundle } from './bundle'; -import { WebpackModule } from './module'; +import { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + Transform, + constKey, + constMemberExpression, + getPropName, + renameParameters, +} from "@webcrack/ast-utils"; +import { Bundle } from "../bundle"; +import { WebpackBundle } from "./bundle"; +import { WebpackModule } from "./module"; export const unpackWebpack = { - name: 'unpack-webpack', - tags: ['unsafe'], + name: "unpack-webpack", + tags: ["unsafe"], + scope: true, visitor(options) { const modules = new Map(); @@ -21,8 +25,8 @@ export const unpackWebpack = { // E.g. [,,function (e, t, i) {...}, ...], index is the module ID m.arrayExpression( m.arrayOf( - m.or(m.functionExpression(), m.arrowFunctionExpression(), null) - ) + m.or(m.functionExpression(), m.arrowFunctionExpression(), null), + ), ), // E.g. {0: function (e, t, i) {...}, ...}, key is the module ID m.objectExpression( @@ -30,14 +34,14 @@ export const unpackWebpack = { m.or( m.objectProperty( m.or(m.numericLiteral(), m.stringLiteral(), m.identifier()), - m.or(m.functionExpression(), m.arrowFunctionExpression()) + m.or(m.functionExpression(), m.arrowFunctionExpression()), ), // __webpack_public_path__ (c: "") - m.objectProperty(constKey('c'), m.stringLiteral()) - ) - ) - ) - ) + m.objectProperty(constKey("c"), m.stringLiteral()), + ), + ), + ), + ), ); const webpack4Matcher = m.callExpression( @@ -53,18 +57,18 @@ export const unpackWebpack = { m.or( // E.g. __webpack_require__.s = 2 m.assignmentExpression( - '=', - constMemberExpression(m.identifier(), 's'), - entryIdMatcher + "=", + constMemberExpression(m.identifier(), "s"), + entryIdMatcher, ), // E.g. return require(0); - m.callExpression(m.identifier(), [entryIdMatcher]) - ) - ) - ) - ) + m.callExpression(m.identifier(), [entryIdMatcher]), + ), + ), + ), + ), ), - [moduleFunctionsMatcher] + [moduleFunctionsMatcher], ); const webpack5Matcher = m.callExpression( @@ -82,54 +86,54 @@ export const unpackWebpack = { m.containerOf( // __webpack_require__.s = 2 m.assignmentExpression( - '=', - constMemberExpression(m.identifier(), 's'), - entryIdMatcher - ) + "=", + constMemberExpression(m.identifier(), "s"), + entryIdMatcher, + ), ), // module.exports = entryModule m.expressionStatement( m.assignmentExpression( - '=', - constMemberExpression(m.identifier(), 'exports'), - m.identifier() - ) - ) - ) - ) - ) + "=", + constMemberExpression(m.identifier(), "exports"), + m.identifier(), + ), + ), + ), + ), + ), ); // Examples: self.webpackChunk_N_E, window.webpackJsonp, this.webpackJsonp const jsonpGlobal = m.capture( constMemberExpression( - m.or(m.identifier(m.or('self', 'window')), m.thisExpression()), - m.matcher(s => s.startsWith('webpack')) - ) + m.or(m.identifier(m.or("self", "window")), m.thisExpression()), + m.matcher((s) => s.startsWith("webpack")), + ), ); // (window.webpackJsonp = window.webpackJsonp || []).push([[0], {...}]) const jsonpMatcher = m.callExpression( constMemberExpression( m.assignmentExpression( - '=', + "=", jsonpGlobal, m.logicalExpression( - '||', + "||", m.fromCapture(jsonpGlobal), - m.arrayExpression([]) - ) + m.arrayExpression([]), + ), ), - 'push' + "push", ), [ m.arrayExpression( m.anyList( - m.arrayExpression([m.numericLiteral()]), // chunkId + m.arrayExpression(m.arrayOf(m.numericLiteral())), // chunkId moduleFunctionsMatcher, - m.slice({ max: 1 }) // optional entry point like [["57iH",19,24,25]] - ) + m.slice({ max: 1 }), // optional entry point like [["57iH",19,24,25]] + ), ), - ] + ], ); return { @@ -143,32 +147,32 @@ export const unpackWebpack = { path.stop(); const modulesPath = path.get( - moduleFunctionsMatcher.currentKeys!.join('.') + moduleFunctionsMatcher.currentKeys!.join("."), ) as NodePath; const moduleWrappers = modulesPath.isArrayExpression() - ? (modulesPath.get('elements') as NodePath[]) - : (modulesPath.get('properties') as NodePath[]); + ? (modulesPath.get("elements") as NodePath[]) + : (modulesPath.get("properties") as NodePath[]); moduleWrappers.forEach((moduleWrapper, index) => { let moduleId = index.toString(); if (t.isObjectProperty(moduleWrapper.node)) { moduleId = getPropName(moduleWrapper.node.key)!; - moduleWrapper = moduleWrapper.get('value') as NodePath; + moduleWrapper = moduleWrapper.get("value") as NodePath; } if ( moduleWrapper.isFunction() && - moduleWrapper.node.body.type === 'BlockStatement' + moduleWrapper.node.body.type === "BlockStatement" ) { - renameParameters(moduleWrapper, ['module', 'exports', 'require']); + renameParameters(moduleWrapper, ["module", "exports", "require"]); const file = t.file(t.program(moduleWrapper.node.body.body)); // Remove /***/ comments between modules (in webpack development builds) const lastNode = file.program.body.at(-1); if ( lastNode?.trailingComments?.length === 1 && - lastNode.trailingComments[0].value === '*' + lastNode.trailingComments[0].value === "*" ) { lastNode.trailingComments = null; } @@ -176,7 +180,7 @@ export const unpackWebpack = { const module = new WebpackModule( moduleId, file, - moduleId === entryIdMatcher.current?.value.toString() + moduleId === entryIdMatcher.current?.value.toString(), ); modules.set(moduleId, module); @@ -184,11 +188,10 @@ export const unpackWebpack = { }); if (modules.size > 0) { - const entryId = entryIdMatcher.current?.value.toString() ?? ''; + const entryId = entryIdMatcher.current?.value.toString() ?? ""; options!.bundle = new WebpackBundle(entryId, modules); } }, - noScope: true, }; }, } satisfies Transform<{ bundle: Bundle | undefined }>; diff --git a/src/extractor/webpack/module.ts b/packages/unpack/src/webpack/module.ts similarity index 56% rename from src/extractor/webpack/module.ts rename to packages/unpack/src/webpack/module.ts index 474e8f29..6745d948 100644 --- a/src/extractor/webpack/module.ts +++ b/packages/unpack/src/webpack/module.ts @@ -1,3 +1,3 @@ -import { Module } from '../module'; +import { Module } from "../module"; export class WebpackModule extends Module {} diff --git a/src/extractor/webpack/varInjection.ts b/packages/unpack/src/webpack/varInjection.ts similarity index 70% rename from src/extractor/webpack/varInjection.ts rename to packages/unpack/src/webpack/varInjection.ts index 52835cc2..fa55a0cb 100644 --- a/src/extractor/webpack/varInjection.ts +++ b/packages/unpack/src/webpack/varInjection.ts @@ -1,8 +1,8 @@ -import { statement } from '@babel/template'; -import { Statement } from '@babel/types'; -import * as m from '@codemod/matchers'; -import { constMemberExpression } from '../../utils/matcher'; -import { WebpackModule } from './module'; +import { statement } from "@babel/template"; +import { Statement } from "@babel/types"; +import * as m from "@codemod/matchers"; +import { constMemberExpression } from "@webcrack/ast-utils"; +import { WebpackModule } from "./module"; const buildVar = statement`var NAME = INIT;`; @@ -25,22 +25,22 @@ export function inlineVarInjections(module: WebpackModule): void { const body = m.capture(m.blockStatement()); const params = m.capture(m.arrayOf(m.identifier())); const args = m.capture( - m.anyList(m.or(m.thisExpression(), m.identifier('exports')), m.oneOrMore()) + m.anyList(m.or(m.thisExpression(), m.identifier("exports")), m.oneOrMore()), ); const matcher = m.expressionStatement( m.callExpression( constMemberExpression( m.functionExpression(undefined, params, body), - 'call' + "call", ), - args - ) + args, + ), ); for (const node of program.body) { if (matcher.match(node)) { const vars = params.current!.map((param, i) => - buildVar({ NAME: param, INIT: args.current![i + 1] }) + buildVar({ NAME: param, INIT: args.current![i + 1] }), ); newBody.push(...vars); newBody.push(...body.current!.body); diff --git a/test/__snapshots__/extractor.test.ts.snap b/packages/unpack/test/__snapshots__/unpack.test.ts.snap similarity index 80% rename from test/__snapshots__/extractor.test.ts.snap rename to packages/unpack/test/__snapshots__/unpack.test.ts.snap index 5478d6ea..030922f4 100644 --- a/test/__snapshots__/extractor.test.ts.snap +++ b/packages/unpack/test/__snapshots__/unpack.test.ts.snap @@ -1,6 +1,41 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`extract browserify.js 1`] = ` +exports[`path mapping 1`] = ` +WebpackBundle { + "entryId": "2", + "modules": Map { + "1" => WebpackModule { + "ast": const a = require("package");, + "id": "1", + "isEntry": false, + "path": "./1.js", + }, + "2" => WebpackModule { + "ast": const a = require("../1.js"); +const _module = 1; +module.exports.color = '#FBC02D'; +{ + const _module2 = 2; + console.log(_module2); + console.log(module); +} +exports.a = 3;, + "id": "2", + "isEntry": true, + "path": "./utils/color.js", + }, + "3" => WebpackModule { + "ast": module.exports = 4;, + "id": "3", + "isEntry": false, + "path": "node_modules/package", + }, + }, + "type": "webpack", +} +`; + +exports[`unpack browserify.js 1`] = ` BrowserifyBundle { "entryId": "2", "modules": Map { @@ -15,10 +50,10 @@ module.exports = add;, "path": "add.js", }, "2" => BrowserifyModule { - "ast": var sum = require("./sum"); + "ast": var sum = require('./sum'); var numbers = [1, 2, 3]; var result = sum(numbers); -var outputElement = document.getElementById("output"); +var outputElement = document.getElementById('output'); outputElement.innerHTML = result;, "dependencies": { "4": "./sum", @@ -41,8 +76,8 @@ module.exports = reduce;, "path": "reduce.js", }, "4" => BrowserifyModule { - "ast": var reduce = require("./reduce"); -var add = require("./add"); + "ast": var reduce = require('./reduce'); +var add = require('./add'); function sum(list) { return reduce(list, add, 0); } @@ -60,7 +95,7 @@ module.exports = sum;, } `; -exports[`extract browserify-2.js 1`] = ` +exports[`unpack browserify-2.js 1`] = ` BrowserifyBundle { "entryId": "2", "modules": Map { @@ -72,8 +107,8 @@ BrowserifyBundle { "path": "lib.js", }, "2" => BrowserifyModule { - "ast": const vscode = require("vscode"); -const lib = require("./lib"); + "ast": const vscode = require('vscode'); +const lib = require('./lib'); console.log(lib);, "dependencies": { "1": "./lib", @@ -87,7 +122,7 @@ console.log(lib);, } `; -exports[`extract webpack.js 1`] = ` +exports[`unpack webpack.js 1`] = ` WebpackBundle { "entryId": "2", "modules": Map { @@ -100,7 +135,7 @@ WebpackBundle { "2" => WebpackModule { "ast": const a = require("./1.js"); const _module = 1; -module.exports.color = "#FBC02D"; +module.exports.color = '#FBC02D'; { const _module2 = 2; console.log(_module2); @@ -122,7 +157,7 @@ exports.a = 3;, } `; -exports[`extract webpack-0.11.x.js 1`] = ` +exports[`unpack webpack-0.11.x.js 1`] = ` WebpackBundle { "entryId": "0", "modules": Map { @@ -130,7 +165,7 @@ WebpackBundle { "ast": require("./1.js"); var template = require("./4.js"); document.write(template({ - hello: "World!" + hello: 'World!' }));, "id": "0", "isEntry": true, @@ -188,7 +223,7 @@ module.exports = function anonymous(locals, attrs, escape, rethrow, merge) { var buf = []; with (locals || {}) { var interp; - buf.push("

    Hello " + escape((interp = hello) == null ? "" : interp) + "

    "); + buf.push('

    Hello ' + escape((interp = hello) == null ? '' : interp) + '

    '); } return buf.join(""); };, @@ -209,7 +244,7 @@ module.exports = function anonymous(locals, attrs, escape, rethrow, merge) { if (!Array.isArray) { Array.isArray = function (arr) { - return Object.prototype.toString.call(arr) == "[object Array]"; + return '[object Array]' == Object.prototype.toString.call(arr); }; } @@ -242,23 +277,19 @@ if (!Object.keys) { */ exports.merge = function merge(a, b) { - var ac = a.class; - var bc = b.class; + var ac = a['class']; + var bc = b['class']; if (ac || bc) { ac = ac || []; bc = bc || []; - if (!Array.isArray(ac)) { - ac = [ac]; - } - if (!Array.isArray(bc)) { - bc = [bc]; - } + if (!Array.isArray(ac)) ac = [ac]; + if (!Array.isArray(bc)) bc = [bc]; ac = ac.filter(nulls); bc = bc.filter(nulls); - a.class = ac.concat(bc).join(" "); + a['class'] = ac.concat(bc).join(' '); } for (var key in b) { - if (key != "class") { + if (key != 'class') { a[key] = b[key]; } } @@ -287,36 +318,32 @@ function nulls(val) { */ exports.attrs = function attrs(obj, escaped) { - var buf = []; - var terse = obj.terse; + var buf = [], + terse = obj.terse; delete obj.terse; - var keys = Object.keys(obj); - var len = keys.length; + var keys = Object.keys(obj), + len = keys.length; if (len) { - buf.push(""); + buf.push(''); for (var i = 0; i < len; ++i) { - var key = keys[i]; - var val = obj[key]; - if (typeof val == "boolean" || val == null) { + var key = keys[i], + val = obj[key]; + if ('boolean' == typeof val || null == val) { if (val) { - if (terse) { - buf.push(key); - } else { - buf.push(key + "=\\"" + key + "\\""); - } + terse ? buf.push(key) : buf.push(key + '="' + key + '"'); } - } else if (key.indexOf("data") == 0 && typeof val != "string") { + } else if (0 == key.indexOf('data') && 'string' != typeof val) { buf.push(key + "='" + JSON.stringify(val) + "'"); - } else if (key == "class" && Array.isArray(val)) { - buf.push(key + "=\\"" + exports.escape(val.join(" ")) + "\\""); + } else if ('class' == key && Array.isArray(val)) { + buf.push(key + '="' + exports.escape(val.join(' ')) + '"'); } else if (escaped && escaped[key]) { - buf.push(key + "=\\"" + exports.escape(val) + "\\""); + buf.push(key + '="' + exports.escape(val) + '"'); } else { - buf.push(key + "=\\"" + val + "\\""); + buf.push(key + '="' + val + '"'); } } } - return buf.join(" "); + return buf.join(' '); }; /** @@ -328,7 +355,7 @@ exports.attrs = function attrs(obj, escaped) { */ exports.escape = function escape(html) { - return String(html).replace(/&(?!(\\w+|\\#\\d+);)/g, "&").replace(//g, ">").replace(/"/g, """); + return String(html).replace(/&(?!(\\w+|\\#\\d+);)/g, '&').replace(//g, '>').replace(/"/g, '"'); }; /** @@ -342,22 +369,22 @@ exports.escape = function escape(html) { */ exports.rethrow = function rethrow(err, filename, lineno) { - if (!filename) { - throw err; - } - var context = 3; - var str = require("./6.js").readFileSync(filename, "utf8"); - var lines = str.split("\\n"); - var start = Math.max(lineno - context, 0); - var end = Math.min(lines.length, lineno + context); // Error context + if (!filename) throw err; + var context = 3, + str = require("./6.js").readFileSync(filename, 'utf8'), + lines = str.split('\\n'), + start = Math.max(lineno - context, 0), + end = Math.min(lines.length, lineno + context); + + // Error context var context = lines.slice(start, end).map(function (line, i) { var curr = i + start + 1; - return (curr == lineno ? " > " : " ") + curr + "| " + line; - }).join("\\n"); + return (curr == lineno ? ' > ' : ' ') + curr + '| ' + line; + }).join('\\n'); // Alter exception message err.path = filename; - err.message = (filename || "Jade") + ":" + lineno + "\\n" + context + "\\n\\n" + err.message; + err.message = (filename || 'Jade') + ':' + lineno + '\\n' + context + '\\n\\n' + err.message; throw err; };, "id": "5", @@ -381,7 +408,7 @@ exports.readFileSync = function (filename) { } `; -exports[`extract webpack-esm.js 1`] = ` +exports[`unpack webpack-esm.js 1`] = ` WebpackBundle { "entryId": "0", "modules": Map { @@ -434,7 +461,7 @@ export default 1;, } `; -exports[`extract webpack-jsonp-chunk.js 1`] = ` +exports[`unpack webpack-jsonp-chunk.js 1`] = ` WebpackBundle { "entryId": "", "modules": Map { @@ -456,18 +483,18 @@ const b = require( /*webcrack:missing*/"./w6GO.js");, } `; -exports[`extract webpack-object.js 1`] = ` +exports[`unpack webpack-object.js 1`] = ` WebpackBundle { "entryId": "386", "modules": Map { "386" => WebpackModule { - "ast": const r = require("./387.js").default;, + "ast": const r = require("./387.js")['default'];, "id": "386", "isEntry": true, "path": "./index.js", }, "387" => WebpackModule { - "ast": module.exports = "test";, + "ast": module.exports = 'test';, "id": "387", "isEntry": false, "path": "./387.js", @@ -477,7 +504,7 @@ WebpackBundle { } `; -exports[`extract webpack-var-injection.js 1`] = ` +exports[`unpack webpack-var-injection.js 1`] = ` WebpackBundle { "entryId": "0", "modules": Map { @@ -506,7 +533,7 @@ console.log(m, n);, } `; -exports[`extract webpack5-esm.js 1`] = ` +exports[`unpack webpack5-esm.js 1`] = ` WebpackBundle { "entryId": "2", "modules": Map { @@ -520,7 +547,7 @@ console.log(lib);, "3" => WebpackModule { "ast": import * as a from "./4.js"; const obj = { - version: "2.0.0" + version: '2.0.0' }; export let version = obj.version; export default a.foo;, @@ -543,7 +570,7 @@ function bar() {}, } `; -exports[`extract webpack5-object.js 1`] = ` +exports[`unpack webpack5-object.js 1`] = ` WebpackBundle { "entryId": "2", "modules": Map { @@ -556,7 +583,7 @@ const _0x8da276 = require(require.ab + "build/Release/spdlog.node");, "path": "./index.js", }, "3" => WebpackModule { - "ast": module.exports = "foo";, + "ast": module.exports = 'foo';, "id": "3", "isEntry": false, "path": "./3.js", @@ -565,38 +592,3 @@ const _0x8da276 = require(require.ab + "build/Release/spdlog.node");, "type": "webpack", } `; - -exports[`extractor > path mapping 1`] = ` -WebpackBundle { - "entryId": "2", - "modules": Map { - "1" => WebpackModule { - "ast": const a = require("package");, - "id": "1", - "isEntry": false, - "path": "./1.js", - }, - "2" => WebpackModule { - "ast": const a = require("../1.js"); -const _module = 1; -module.exports.color = "#FBC02D"; -{ - const _module2 = 2; - console.log(_module2); - console.log(module); -} -exports.a = 3;, - "id": "2", - "isEntry": true, - "path": "./utils/color.js", - }, - "3" => WebpackModule { - "ast": module.exports = 4;, - "id": "3", - "isEntry": false, - "path": "node_modules/package", - }, - }, - "type": "webpack", -} -`; diff --git a/packages/unpack/test/path.test.ts b/packages/unpack/test/path.test.ts new file mode 100644 index 00000000..8c3cc145 --- /dev/null +++ b/packages/unpack/test/path.test.ts @@ -0,0 +1,76 @@ +import { expect, test } from "vitest"; +import { relativePath, resolveDependencyTree } from "../src/path"; + +test("relative paths", () => { + expect(relativePath("./a.js", "./x/y.js")).toBe("./x/y.js"); + expect(relativePath("./x/y.js", "./a.js")).toBe("../a.js"); + expect(relativePath("./a.js", "node_modules/lib")).toBe("lib"); +}); + +test("resolve browserify paths", () => { + const dependencies = { + 0: { 1: "./a.js", 4: "lib" }, + 1: { 2: "../bar/b.js" }, + 2: { 3: "../../c.js" }, + 3: {}, + 4: {}, + }; + expect(resolveDependencyTree(dependencies, "0")).toEqual({ + 0: "tmp0/tmp1/index.js", + 1: "tmp0/tmp1/a.js", + 2: "tmp0/bar/b.js", + 3: "c.js", + 4: "node_modules/lib/index.js", + }); +}); + +test("resolve browserify paths 2", () => { + const dependencies = { + 1: {}, + 2: { 5: "./v1", 6: "./v4" }, + 3: {}, + 4: {}, + 5: { 3: "./lib/bytesToUuid", 4: "./lib/rng" }, + 6: { 3: "./lib/bytesToUuid", 4: "./lib/rng" }, + 7: { 1: "number", 2: "uuid" }, + }; + expect(resolveDependencyTree(dependencies, "7")).toEqual({ + 1: "node_modules/number/index.js", + 2: "node_modules/uuid/index.js", + 3: "node_modules/uuid/lib/bytesToUuid.js", + 4: "node_modules/uuid/lib/rng.js", + 5: "node_modules/uuid/v1.js", + 6: "node_modules/uuid/v4.js", + 7: "index.js", + }); +}); + +// FIXME: utils/index.js instead of utils.js, can only know the real path by +// checking if all relative paths point to the correct modules? +test.skip("resolve browserify paths with index directory", () => { + const dependencies = { + 1: { 2: "./utils", 4: "./test" }, + 2: { 3: "./lib", 4: "../test" }, + 3: {}, + 4: {}, + }; + expect(resolveDependencyTree(dependencies, "1")).toEqual({ + 1: "index.js", + 2: "utils/index.js", + 3: "utils/lib.js", + 4: "test.js", + }); +}); + +test("resolve circular browserify paths", () => { + const dependencies = { + 1: { 2: "./utils" }, + 2: { 1: "./base64" }, + 3: { 1: "./base64" }, + }; + expect(resolveDependencyTree(dependencies, "3")).toEqual({ + 1: "base64.js", + 2: "utils.js", + 3: "index.js", + }); +}); diff --git a/test/samples/browserify-2.js b/packages/unpack/test/samples/browserify-2.js similarity index 100% rename from test/samples/browserify-2.js rename to packages/unpack/test/samples/browserify-2.js diff --git a/test/samples/browserify-webpack-nested.js b/packages/unpack/test/samples/browserify-webpack-nested.js similarity index 100% rename from test/samples/browserify-webpack-nested.js rename to packages/unpack/test/samples/browserify-webpack-nested.js diff --git a/test/samples/browserify.js b/packages/unpack/test/samples/browserify.js similarity index 100% rename from test/samples/browserify.js rename to packages/unpack/test/samples/browserify.js diff --git a/test/samples/webpack-0.11.x.js b/packages/unpack/test/samples/webpack-0.11.x.js similarity index 100% rename from test/samples/webpack-0.11.x.js rename to packages/unpack/test/samples/webpack-0.11.x.js diff --git a/test/samples/webpack-esm.js b/packages/unpack/test/samples/webpack-esm.js similarity index 100% rename from test/samples/webpack-esm.js rename to packages/unpack/test/samples/webpack-esm.js diff --git a/test/samples/webpack-jsonp-chunk.js b/packages/unpack/test/samples/webpack-jsonp-chunk.js similarity index 100% rename from test/samples/webpack-jsonp-chunk.js rename to packages/unpack/test/samples/webpack-jsonp-chunk.js diff --git a/test/samples/webpack-object.js b/packages/unpack/test/samples/webpack-object.js similarity index 100% rename from test/samples/webpack-object.js rename to packages/unpack/test/samples/webpack-object.js diff --git a/test/samples/webpack-path-traversal.js b/packages/unpack/test/samples/webpack-path-traversal.js similarity index 100% rename from test/samples/webpack-path-traversal.js rename to packages/unpack/test/samples/webpack-path-traversal.js diff --git a/test/samples/webpack-var-injection.js b/packages/unpack/test/samples/webpack-var-injection.js similarity index 100% rename from test/samples/webpack-var-injection.js rename to packages/unpack/test/samples/webpack-var-injection.js diff --git a/test/samples/webpack.js b/packages/unpack/test/samples/webpack.js similarity index 100% rename from test/samples/webpack.js rename to packages/unpack/test/samples/webpack.js diff --git a/test/samples/webpack5-esm.js b/packages/unpack/test/samples/webpack5-esm.js similarity index 100% rename from test/samples/webpack5-esm.js rename to packages/unpack/test/samples/webpack5-esm.js diff --git a/test/samples/webpack5-object.js b/packages/unpack/test/samples/webpack5-object.js similarity index 100% rename from test/samples/webpack5-object.js rename to packages/unpack/test/samples/webpack5-object.js diff --git a/packages/unpack/test/setup.ts b/packages/unpack/test/setup.ts new file mode 100644 index 00000000..f50b672e --- /dev/null +++ b/packages/unpack/test/setup.ts @@ -0,0 +1,8 @@ +import * as t from "@babel/types"; +import { generate } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +expect.addSnapshotSerializer({ + test: (val: unknown) => t.isNode(val) && !("parentPath" in val), + serialize: (val: t.Node) => generate(val), +}); diff --git a/packages/unpack/test/unpack.test.ts b/packages/unpack/test/unpack.test.ts new file mode 100644 index 00000000..38121d47 --- /dev/null +++ b/packages/unpack/test/unpack.test.ts @@ -0,0 +1,59 @@ +import * as m from "@codemod/matchers"; +import assert from "assert"; +import { readFile } from "fs/promises"; +import { join } from "path"; +import { expect, test } from "vitest"; +import { unpack } from "../src/index"; + +// Test samples +test.each([ + "webpack.js", + "webpack-object.js", + "webpack-esm.js", + "webpack-var-injection.js", + "webpack-jsonp-chunk.js", + "webpack-0.11.x.js", + "webpack5-object.js", + "webpack5-esm.js", + "browserify.js", + "browserify-2.js", +])("unpack %s", async (filename) => { + const bundle = unpack( + await readFile(join(__dirname, "samples", filename), "utf8"), + ); + expect(bundle).toMatchSnapshot(); +}); + +test("detect top-level bundle first", async () => { + const bundle = unpack( + await readFile( + join(__dirname, "samples/browserify-webpack-nested.js"), + "utf8", + ), + ); + assert(bundle); + expect(bundle.type).toBe("browserify"); +}); + +test("path mapping", async () => { + const bundle = unpack( + await readFile(join(__dirname, "samples/webpack.js"), "utf8"), + { + "./utils/color.js": m.stringLiteral("#FBC02D"), + package: m.numericLiteral(4), + }, + ); + expect(bundle).toBeDefined(); + assert(bundle); + expect(bundle).toMatchSnapshot(); +}); + +test.skip("prevent path traversal", async () => { + // const code = await readFile( + // join(__dirname, "samples/webpack-path-traversal.js"), + // "utf8", + // ); + // const result = await webcrack(code); + // const dir = join(tmpdir(), "path-traversal-test"); + // await expect(result.save(dir)).rejects.toThrow("path traversal"); +}); diff --git a/packages/unpack/tsconfig.json b/packages/unpack/tsconfig.json new file mode 100644 index 00000000..fca8f92b --- /dev/null +++ b/packages/unpack/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@webcrack/typescript-config/base.json", +} diff --git a/packages/unpack/vitest.config.ts b/packages/unpack/vitest.config.ts new file mode 100644 index 00000000..cd893d71 --- /dev/null +++ b/packages/unpack/vitest.config.ts @@ -0,0 +1,11 @@ +import { join } from "node:path"; +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + root: join(__dirname, "test"), + setupFiles: "setup.ts", + include: ["**/*.test.ts"], + isolate: false, + }, +}); diff --git a/packages/webcrack/.eslintrc.cjs b/packages/webcrack/.eslintrc.cjs new file mode 100644 index 00000000..f642de96 --- /dev/null +++ b/packages/webcrack/.eslintrc.cjs @@ -0,0 +1,6 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@webcrack/eslint-config/index.js"], + ignorePatterns: ["tmp/**/*", "test/samples/**/*"], +}; diff --git a/packages/webcrack/.gitignore b/packages/webcrack/.gitignore new file mode 100644 index 00000000..a9a5aecf --- /dev/null +++ b/packages/webcrack/.gitignore @@ -0,0 +1 @@ +tmp diff --git a/packages/webcrack/README.md b/packages/webcrack/README.md new file mode 100644 index 00000000..bf69c52b --- /dev/null +++ b/packages/webcrack/README.md @@ -0,0 +1 @@ +# `webcrack` diff --git a/esbuild.config.js b/packages/webcrack/esbuild.config.js similarity index 85% rename from esbuild.config.js rename to packages/webcrack/esbuild.config.js index dc9123c9..bef965ff 100644 --- a/esbuild.config.js +++ b/packages/webcrack/esbuild.config.js @@ -33,30 +33,20 @@ const babelImportPlugin = { */ const configs = [ { - platform: 'node', entryPoints: ['src/index.ts'], - outdir: 'dist', }, { - platform: 'node', entryPoints: ['src/cli.ts'], - outdir: 'dist', bundle: false, }, - { - platform: 'browser', - entryPoints: ['src/index.ts'], - outfile: 'dist/browser.js', - }, ]; for (const config of configs) { const ctx = await esbuild.context({ bundle: true, format: 'esm', - define: { - 'process.env.browser': String(config.platform === 'browser'), - }, + platform: 'node', + outdir: 'dist', sourcemap: true, packages: 'external', plugins: [babelImportPlugin], diff --git a/packages/webcrack/package.json b/packages/webcrack/package.json new file mode 100644 index 00000000..76a1fb61 --- /dev/null +++ b/packages/webcrack/package.json @@ -0,0 +1,68 @@ +{ + "name": "webcrack", + "version": "2.10.0", + "description": "Deobfuscate, unminify and unpack bundled javascript", + "author": "j4k0xb", + "license": "MIT", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": "dist/cli.js", + "files": [ + "dist" + ], + "scripts": { + "build": "node esbuild.config.js && tsc -p tsconfig.build.json", + "watch": "node esbuild.config.js --watch", + "start": "node dist/cli.js", + "tmp": "node esbuild.config.js && node --enable-source-maps dist/cli.js tmp/test.js -f -o tmp/webcrack-out", + "lint": "eslint src test", + "lint:fix": "eslint src test --fix", + "test": "vitest" + }, + "repository": { + "type": "git", + "url": "https://github.com/j4k0xb/webcrack" + }, + "homepage": "https://webcrack.netlify.app", + "keywords": [ + "webpack", + "bundle", + "extract", + "reverse-engineering", + "ast", + "deobfuscation", + "unpack", + "debundle", + "deobfuscator", + "unminify", + "unbundle" + ], + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "@codemod/matchers": "^1.7.0", + "@webcrack/ast-utils": "workspace:*", + "@webcrack/deobfuscate": "workspace:*", + "@webcrack/unminify": "workspace:*", + "@webcrack/unpack": "workspace:*", + "babel-plugin-minify-mangle-names": "^0.5.1", + "commander": "^11.1.0", + "debug": "^4.3.4" + }, + "devDependencies": { + "@types/babel__generator": "^7.6.7", + "@types/babel__helper-validator-identifier": "^7.15.2", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.20.4", + "@types/debug": "^4.1.12", + "@types/node": "^20.10.1", + "@webcrack/eslint-config": "workspace:*", + "@webcrack/typescript-config": "workspace:*", + "esbuild": "^0.19.8", + "typescript": "^5.3.2" + } +} diff --git a/packages/webcrack/src/cli.ts b/packages/webcrack/src/cli.ts new file mode 100644 index 00000000..29da7440 --- /dev/null +++ b/packages/webcrack/src/cli.ts @@ -0,0 +1,63 @@ +#!/usr/bin/env node + +import { program } from "commander"; +import debug from "debug"; +import { existsSync, readFileSync } from "node:fs"; +import { readFile, rm } from "node:fs/promises"; +import { join } from "node:path"; +import * as url from "node:url"; +import { webcrack } from "./index.js"; + +const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); +const { version, description } = JSON.parse( + readFileSync(join(__dirname, "..", "package.json"), "utf8"), +) as { version: string; description: string }; + +debug.enable("webcrack:*"); + +interface Options { + force: boolean; + output?: string; + mangle?: boolean; +} + +async function readStdin() { + let data = ""; + process.stdin.setEncoding("utf8"); + for await (const chunk of process.stdin) data += chunk; + return data; +} + +program + .version(version) + .description(description) + .option("-o, --output ", "output directory for bundled files") + .option("-f, --force", "overwrite output directory") + .option("-m, --mangle", "mangle variable names") + .argument("[file]", "input file, defaults to stdin") + .action(async (input: string | undefined) => { + const { output, force, mangle } = program.opts(); + const code = await (input ? readFile(input, "utf8") : readStdin()); + + if (output) { + if (force || !existsSync(output)) { + await rm(output, { recursive: true, force: true }); + } else { + program.error("output directory already exists"); + } + } + + const result = await webcrack(code, { mangle }); + + if (output) { + await result.save(output); + } else { + console.log(result.code); + if (result.bundle) { + debug("webcrack:unpack")( + `${result.bundle.modules.size} modules are not displayed in the terminal. Use the --output option to save them`, + ); + } + } + }) + .parse(); diff --git a/packages/webcrack/src/index.ts b/packages/webcrack/src/index.ts new file mode 100644 index 00000000..2d0438ed --- /dev/null +++ b/packages/webcrack/src/index.ts @@ -0,0 +1,179 @@ +import { ParseResult, parse } from "@babel/parser"; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + applyTransform, + applyTransformAsync, + applyTransforms, + generate, +} from "@webcrack/ast-utils"; +import deobfuscate, { + Sandbox, + createBrowserSandbox, + createNodeSandbox, +} from "@webcrack/deobfuscate"; +import debugProtection from "@webcrack/deobfuscate/src/debug-protection"; +import mergeObjectAssignments from "@webcrack/deobfuscate/src/merge-object-assignments"; +import selfDefending from "@webcrack/deobfuscate/src/self-defending"; +import { unminify } from "@webcrack/unminify"; +import { + blockStatements, + sequence, + splitVariableDeclarations, +} from "@webcrack/unminify/transforms"; +import { Bundle, unpackAST } from "@webcrack/unpack"; +import debug from "debug"; +import { join, normalize } from "node:path"; +import jsx from "./transforms/jsx"; +import jsxNew from "./transforms/jsx-new"; +import mangle from "./transforms/mangle"; +import { isBrowser } from "./utils/platform"; + +export { type Sandbox } from "@webcrack/deobfuscate"; + +export interface WebcrackResult { + code: string; + bundle: Bundle | undefined; + /** + * Save the deobufscated code and the extracted bundle to the given directory. + * @param path Output directory + */ + save(path: string): Promise; +} + +export interface Options { + /** + * Decompile react components to JSX. + * @default true + */ + jsx?: boolean; + /** + * Extract modules from the bundle. + * @default true + */ + unpack?: boolean; + /** + * Deobfuscate the code. + * @default true + */ + deobfuscate?: boolean; + /** + * Mangle variable names. + * @default false + */ + mangle?: boolean; + /** + * Assigns paths to modules based on the given matchers. + * This will also rewrite `require()` calls to use the new paths. + * + * @example + * ```js + * m => ({ + * './utils/color.js': m.regExpLiteral('^#([0-9a-f]{3}){1,2}$') + * }) + * ``` + */ + mappings?: ( + m: typeof import("@codemod/matchers"), + ) => Record>; + /** + * Function that executes a code expression and returns the result (typically from the obfuscator). + */ + sandbox?: Sandbox; + /** + * @param progress Progress in percent (0-100) + */ + onProgress?: (progress: number) => void; +} + +function mergeOptions(options: Options): asserts options is Required { + const mergedOptions: Required = { + jsx: true, + unpack: true, + deobfuscate: true, + mangle: false, + mappings: () => ({}), + onProgress: () => {}, + sandbox: isBrowser() ? createBrowserSandbox() : createNodeSandbox(), + ...options, + }; + Object.assign(options, mergedOptions); +} + +export async function webcrack( + code: string, + options: Options = {}, +): Promise { + mergeOptions(options); + options.onProgress(0); + + if (isBrowser()) { + debug.enable("webcrack:*"); + } + + const isBookmarklet = /^javascript:./.test(code); + if (isBookmarklet) { + code = decodeURIComponent(code.replace(/^javascript:/, "")); + } + + let ast: ParseResult = null!; + let outputCode = ""; + let bundle: Bundle | undefined; + + const stages = [ + () => { + return (ast = parse(code, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + plugins: ["jsx"], + })); + }, + () => { + return applyTransforms(ast, [ + blockStatements, + sequence, + splitVariableDeclarations, + ]); + }, + options.deobfuscate && + (() => applyTransformAsync(ast, deobfuscate, options.sandbox)), + () => { + applyTransform(ast, unminify); + }, + options.mangle && (() => applyTransform(ast, mangle)), + // TODO: Also merge unminify visitor (breaks selfDefending/debugProtection atm) + (options.deobfuscate || options.jsx) && + (() => { + return applyTransforms( + ast, + [ + // Have to run this after unminify to properly detect it + options.deobfuscate ? [selfDefending, debugProtection] : [], + options.jsx ? [jsx, jsxNew] : [], + ].flat(), + ); + }), + options.deobfuscate && (() => applyTransform(ast, mergeObjectAssignments)), + () => (outputCode = generate(ast)), + // Unpacking modifies the same AST and may result in imports not at top level + // so the code has to be generated before + options.unpack && (() => (bundle = unpackAST(ast, options.mappings(m)))), + ].filter(Boolean) as (() => unknown)[]; + + for (let i = 0; i < stages.length; i++) { + await stages[i](); + options.onProgress((100 / stages.length) * (i + 1)); + } + + return { + code: outputCode, + bundle, + async save(path) { + const { mkdir, writeFile } = await import("node:fs/promises"); + path = normalize(path); + await mkdir(path, { recursive: true }); + await writeFile(join(path, "deobfuscated.js"), outputCode, "utf8"); + await bundle?.save(path); + }, + }; +} diff --git a/packages/webcrack/src/matchers.d.ts b/packages/webcrack/src/matchers.d.ts new file mode 100644 index 00000000..01526964 --- /dev/null +++ b/packages/webcrack/src/matchers.d.ts @@ -0,0 +1,41 @@ +import { Matcher } from "@codemod/matchers"; + +type MatcherType = T extends Matcher ? U : T; + +declare module "@codemod/matchers" { + // The library only implements up to 5 arguments, but we need more + // Also have to keep the other ones because of recursive matchers (numberExpressions.ts) + + export function or(): Matcher; + export function or(first: Matcher | T): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + ): Matcher; + export function or( + first: Matcher | T, + second: Matcher | U, + third: Matcher | V, + fourth: Matcher | W, + fifth: Matcher | X, + ): Matcher; + export function or( + ...matchers: T + ): Matcher>; +} + +declare module "@codemod/matchers/build/matchers/predicate" { + // Convenience overload for not having to cast the value when using it + export function predicate(predicate: (value: T) => boolean): Matcher; +} diff --git a/src/transforms/babel-plugin-minify-mangle-names.d.ts b/packages/webcrack/src/transforms/babel-plugin-minify-mangle-names.d.ts similarity index 52% rename from src/transforms/babel-plugin-minify-mangle-names.d.ts rename to packages/webcrack/src/transforms/babel-plugin-minify-mangle-names.d.ts index b615c69a..1d2bf3f3 100644 --- a/src/transforms/babel-plugin-minify-mangle-names.d.ts +++ b/packages/webcrack/src/transforms/babel-plugin-minify-mangle-names.d.ts @@ -1,6 +1,6 @@ -declare module 'babel-plugin-minify-mangle-names' { - import { Visitor, traverse } from '@babel/traverse'; - import * as t from '@babel/types'; +declare module "babel-plugin-minify-mangle-names" { + import { Visitor, traverse } from "@babel/traverse"; + import * as t from "@babel/types"; export default function mangle(babel: Babel): { visitor: Visitor; diff --git a/src/transforms/jsx-new.ts b/packages/webcrack/src/transforms/jsx-new.ts similarity index 75% rename from src/transforms/jsx-new.ts rename to packages/webcrack/src/transforms/jsx-new.ts index f4a4e44d..aa78f490 100644 --- a/src/transforms/jsx-new.ts +++ b/packages/webcrack/src/transforms/jsx-new.ts @@ -1,42 +1,45 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; -import { codePreview } from '../utils/ast'; -import { constMemberExpression } from '../utils/matcher'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + Transform, + codePreview, + constMemberExpression, +} from "@webcrack/ast-utils"; /** * https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md * https://new-jsx-transform.netlify.app/ */ export default { - name: 'jsx-new', - tags: ['unsafe'], + name: "jsx-new", + tags: ["unsafe"], + scope: true, visitor: () => { const deepIdentifierMemberExpression = m.memberExpression( m.or( m.identifier(), - m.matcher(node => deepIdentifierMemberExpression.match(node)) + m.matcher((node) => deepIdentifierMemberExpression.match(node)), ), m.identifier(), - false + false, ); const type = m.capture( m.or( m.identifier(), // jsx(Component, ...) m.stringLiteral(), // jsx('div', ...) - deepIdentifierMemberExpression // jsx(Component.SubComponent, ...) - ) + deepIdentifierMemberExpression, // jsx(Component.SubComponent, ...) + ), ); - const fragmentType = constMemberExpression('React', 'Fragment'); + const fragmentType = constMemberExpression("React", "Fragment"); const props = m.capture(m.objectExpression()); const key = m.capture(m.anyExpression()); - const jsxFunction = m.capture(m.or('jsx' as const, 'jsxs' as const)); + const jsxFunction = m.capture(m.or("jsx" as const, "jsxs" as const)); // jsx(type, props, key?) const jsxMatcher = m.callExpression( m.identifier(jsxFunction), - m.anyList(type, props, m.slice({ min: 0, max: 1, matcher: key })) + m.anyList(type, props, m.slice({ min: 0, max: 1, matcher: key })), ); return { @@ -55,7 +58,7 @@ export default { ) { const binding = path.scope.getBinding(type.current.name); if (!binding) return; - name = t.jsxIdentifier(path.scope.generateUid('Component')); + name = t.jsxIdentifier(path.scope.generateUid("Component")); path.scope.rename(type.current.name, name.name); } @@ -63,14 +66,14 @@ export default { if (path.node.arguments.length === 3) { attributes.push( t.jsxAttribute( - t.jsxIdentifier('key'), - convertAttributeValue(key.current!) - ) + t.jsxIdentifier("key"), + convertAttributeValue(key.current!), + ), ); } const children = convertChildren( props.current!, - jsxFunction.current! + jsxFunction.current!, ); if (isFragment && attributes.length === 0) { @@ -88,7 +91,6 @@ export default { this.changes++; }, }, - noScope: true, }; }, } satisfies Transform; @@ -99,7 +101,7 @@ export default { * - `'div'` -> `div` */ function convertType( - type: t.Identifier | t.MemberExpression | t.StringLiteral + type: t.Identifier | t.MemberExpression | t.StringLiteral, ): t.JSXIdentifier | t.JSXMemberExpression { if (t.isIdentifier(type)) { return t.jsxIdentifier(type.name); @@ -107,7 +109,7 @@ function convertType( return t.jsxIdentifier(type.value); } else { const object = convertType( - type.object as t.Identifier | t.MemberExpression + type.object as t.Identifier | t.MemberExpression, ); const property = t.jsxIdentifier((type.property as t.Identifier).name); return t.jsxMemberExpression(object, property); @@ -120,18 +122,18 @@ function convertType( * `className='foo' style={{ display: 'block' }}` */ function convertAttributes( - object: t.ObjectExpression + object: t.ObjectExpression, ): (t.JSXAttribute | t.JSXSpreadAttribute)[] { const name = m.capture(m.anyString()); const value = m.capture(m.anyExpression()); const matcher = m.objectProperty( m.or(m.identifier(name), m.stringLiteral(name)), - value + value, ); - return object.properties.flatMap(property => { + return object.properties.flatMap((property) => { if (matcher.match(property)) { - if (name.current === 'children') return []; + if (name.current === "children") return []; const jsxName = t.jsxIdentifier(name.current!); const jsxValue = convertAttributeValue(value.current!); @@ -140,43 +142,43 @@ function convertAttributes( return t.jsxSpreadAttribute(property.argument); } else { throw new Error( - `jsx: property type not implemented ${codePreview(object)}` + `jsx: property type not implemented ${codePreview(object)}`, ); } }); } function convertAttributeValue( - expression: t.Expression + expression: t.Expression, ): t.JSXExpressionContainer | t.StringLiteral { - return expression.type === 'StringLiteral' + return expression.type === "StringLiteral" ? expression : t.jsxExpressionContainer(expression); } function convertChildren( object: t.ObjectExpression, - fn: 'jsx' | 'jsxs' + fn: "jsx" | "jsxs", ): (t.JSXText | t.JSXElement | t.JSXExpressionContainer)[] { const children = m.capture(m.anyExpression()); const matcher = m.objectProperty( - m.or(m.identifier('children'), m.stringLiteral('children')), - children + m.or(m.identifier("children"), m.stringLiteral("children")), + children, ); - const prop = object.properties.find(prop => matcher.match(prop)); + const prop = object.properties.find((prop) => matcher.match(prop)); if (!prop) return []; - if (fn === 'jsxs' && t.isArrayExpression(children.current)) { - return children.current.elements.map(child => - convertChild(child as t.Expression) + if (fn === "jsxs" && t.isArrayExpression(children.current)) { + return children.current.elements.map((child) => + convertChild(child as t.Expression), ); } return [convertChild(children.current!)]; } function convertChild( - child: t.Expression + child: t.Expression, ): t.JSXElement | t.JSXExpressionContainer | t.JSXText { if (t.isJSXElement(child)) { return child; diff --git a/src/transforms/jsx.ts b/packages/webcrack/src/transforms/jsx.ts similarity index 77% rename from src/transforms/jsx.ts rename to packages/webcrack/src/transforms/jsx.ts index e8367d83..8813ffa6 100644 --- a/src/transforms/jsx.ts +++ b/packages/webcrack/src/transforms/jsx.ts @@ -1,45 +1,48 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; -import { codePreview } from '../utils/ast'; -import { constMemberExpression } from '../utils/matcher'; +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { + Transform, + codePreview, + constMemberExpression, +} from "@webcrack/ast-utils"; export default { - name: 'jsx', - tags: ['unsafe'], + name: "jsx", + tags: ["unsafe"], + scope: true, visitor: () => { const deepIdentifierMemberExpression = m.memberExpression( m.or( m.identifier(), - m.matcher(node => deepIdentifierMemberExpression.match(node)) + m.matcher((node) => deepIdentifierMemberExpression.match(node)), ), m.identifier(), - false + false, ); const type = m.capture( m.or( m.identifier(), // React.createElement(Component, ...) m.stringLiteral(), // React.createElement('div', ...) - deepIdentifierMemberExpression // React.createElement(Component.SubComponent, ...) - ) + deepIdentifierMemberExpression, // React.createElement(Component.SubComponent, ...) + ), ); const props = m.capture(m.or(m.objectExpression(), m.nullLiteral())); // React.createElement(type, props, ...children) const elementMatcher = m.callExpression( - constMemberExpression('React', 'createElement'), - m.anyList(type, props, m.zeroOrMore(m.anyExpression())) + constMemberExpression("React", "createElement"), + m.anyList(type, props, m.zeroOrMore(m.anyExpression())), ); // React.createElement(React.Fragment, null, ...children) const fragmentMatcher = m.callExpression( - constMemberExpression('React', 'createElement'), + constMemberExpression("React", "createElement"), m.anyList( - constMemberExpression('React', 'Fragment'), + constMemberExpression("React", "Fragment"), m.nullLiteral(), - m.zeroOrMore(m.anyExpression()) - ) + m.zeroOrMore(m.anyExpression()), + ), ); return { @@ -47,7 +50,7 @@ export default { exit(path) { if (fragmentMatcher.match(path.node)) { const children = convertChildren( - path.node.arguments.slice(2) as t.Expression[] + path.node.arguments.slice(2) as t.Expression[], ); const opening = t.jsxOpeningFragment(); const closing = t.jsxClosingFragment(); @@ -67,7 +70,7 @@ export default { ) { const binding = path.scope.getBinding(type.current.name); if (!binding) return; - name = t.jsxIdentifier(path.scope.generateUid('Component')); + name = t.jsxIdentifier(path.scope.generateUid("Component")); path.scope.rename(type.current.name, name.name); } @@ -75,7 +78,7 @@ export default { ? convertAttributes(props.current) : []; const children = convertChildren( - path.node.arguments.slice(2) as t.Expression[] + path.node.arguments.slice(2) as t.Expression[], ); const selfClosing = children.length === 0; const opening = t.jsxOpeningElement(name, attributes, selfClosing); @@ -86,7 +89,6 @@ export default { } }, }, - noScope: true, }; }, } satisfies Transform; @@ -97,7 +99,7 @@ export default { * - `'div'` -> `div` */ function convertType( - type: t.Identifier | t.MemberExpression | t.StringLiteral + type: t.Identifier | t.MemberExpression | t.StringLiteral, ): t.JSXIdentifier | t.JSXMemberExpression { if (t.isIdentifier(type)) { return t.jsxIdentifier(type.name); @@ -105,7 +107,7 @@ function convertType( return t.jsxIdentifier(type.value); } else { const object = convertType( - type.object as t.Identifier | t.MemberExpression + type.object as t.Identifier | t.MemberExpression, ); const property = t.jsxIdentifier((type.property as t.Identifier).name); return t.jsxMemberExpression(object, property); @@ -118,20 +120,20 @@ function convertType( * `className='foo' style={{ display: 'block' }}` */ function convertAttributes( - object: t.ObjectExpression + object: t.ObjectExpression, ): (t.JSXAttribute | t.JSXSpreadAttribute)[] { const name = m.capture(m.anyString()); const value = m.capture(m.anyExpression()); const matcher = m.objectProperty( m.or(m.identifier(name), m.stringLiteral(name)), - value + value, ); - return object.properties.map(property => { + return object.properties.map((property) => { if (matcher.match(property)) { const jsxName = t.jsxIdentifier(name.current!); const jsxValue = - value.current!.type === 'StringLiteral' + value.current!.type === "StringLiteral" ? value.current : t.jsxExpressionContainer(value.current!); return t.jsxAttribute(jsxName, jsxValue); @@ -139,16 +141,16 @@ function convertAttributes( return t.jsxSpreadAttribute(property.argument); } else { throw new Error( - `jsx: property type not implemented ${codePreview(object)}` + `jsx: property type not implemented ${codePreview(object)}`, ); } }); } function convertChildren( - children: t.Expression[] + children: t.Expression[], ): (t.JSXText | t.JSXElement | t.JSXExpressionContainer)[] { - return children.map(child => { + return children.map((child) => { if (t.isJSXElement(child)) { return child; } else if (t.isStringLiteral(child)) { diff --git a/src/transforms/mangle.ts b/packages/webcrack/src/transforms/mangle.ts similarity index 62% rename from src/transforms/mangle.ts rename to packages/webcrack/src/transforms/mangle.ts index 15937c18..99c34d0f 100644 --- a/src/transforms/mangle.ts +++ b/packages/webcrack/src/transforms/mangle.ts @@ -1,16 +1,17 @@ -import traverse, { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import mangle from 'babel-plugin-minify-mangle-names'; -import { Transform } from '.'; +import traverse, { NodePath } from "@babel/traverse"; +import * as t from "@babel/types"; +import { Transform } from "@webcrack/ast-utils"; +import mangle from "babel-plugin-minify-mangle-names"; export default { - name: 'mangle', - tags: ['safe'], + name: "mangle", + tags: ["safe"], + scope: true, run(ast) { // path.hub is undefined for some reason, monkey-patch to avoid error... // eslint-disable-next-line @typescript-eslint/unbound-method const { getSource } = NodePath.prototype; - NodePath.prototype.getSource = () => ''; + NodePath.prototype.getSource = () => ""; traverse(ast, mangle({ types: t, traverse }).visitor, undefined, { opts: { diff --git a/packages/webcrack/src/utils/platform.ts b/packages/webcrack/src/utils/platform.ts new file mode 100644 index 00000000..4ea2e290 --- /dev/null +++ b/packages/webcrack/src/utils/platform.ts @@ -0,0 +1,3 @@ +export function isBrowser(): boolean { + return typeof window !== "undefined" || typeof importScripts !== "undefined"; +} diff --git a/packages/webcrack/test/api.test.ts b/packages/webcrack/test/api.test.ts new file mode 100644 index 00000000..68f53b1e --- /dev/null +++ b/packages/webcrack/test/api.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, test } from "vitest"; +import { webcrack } from "../src"; + +// const obfuscatedSrc = await readFile( +// join(__dirname, "samples/obfuscator.io.js"), +// "utf8", +// ); +// const webpackSrc = await readFile( +// join(__dirname, "samples/webpack.js"), +// "utf8", +// ); + +describe("options", () => { + test.skip("no deobfuscate", async () => { + // await webcrack(webpackSrc, { deobfuscate: false }); + }); + + test.skip("no unpack", async () => { + // const result = await webcrack(webpackSrc, { unpack: false }); + // expect(result.bundle).toBeUndefined(); + }); + + test("no jsx", async () => { + const result = await webcrack('React.createElement("div", null)', { + jsx: false, + }); + expect(result.code).toBe('React.createElement("div", null);'); + }); + + test.skip("custom sandbox", async () => { + // const sandbox = vi.fn((code: string) => + // /* isolated-vm or something */ Promise.resolve(code), + // ); + // await webcrack(obfuscatedSrc, { sandbox }); + // expect(sandbox).toHaveBeenCalledOnce(); + }); + + test("mangle", async () => { + const result = await webcrack("const foo = 1;", { mangle: true }); + expect(result.code).not.contain("foo"); + }); +}); diff --git a/packages/webcrack/test/setup.ts b/packages/webcrack/test/setup.ts new file mode 100644 index 00000000..f50b672e --- /dev/null +++ b/packages/webcrack/test/setup.ts @@ -0,0 +1,8 @@ +import * as t from "@babel/types"; +import { generate } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +expect.addSnapshotSerializer({ + test: (val: unknown) => t.isNode(val) && !("parentPath" in val), + serialize: (val: t.Node) => generate(val), +}); diff --git a/packages/webcrack/test/transforms.test.ts b/packages/webcrack/test/transforms.test.ts new file mode 100644 index 00000000..056bc40a --- /dev/null +++ b/packages/webcrack/test/transforms.test.ts @@ -0,0 +1,145 @@ +import { parse } from "@babel/parser"; +import { Transform, applyTransform } from "@webcrack/ast-utils"; +import { Assertion, describe as describeVitest, expect, test } from "vitest"; +import { webcrack } from "../src"; +import jsx from "../src/transforms/jsx"; +import jsxNew from "../src/transforms/jsx-new"; + +function describe( + transform: Transform, + factory: ( + expect: (actualCode: string, options?: Options) => Assertion, + ) => void, +) { + return describeVitest(transform.name, () => { + factory((actualCode, options) => { + const ast = parse(actualCode, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + }); + applyTransform(ast, transform, options); + return expect(ast); + }); + }); +} + +test("decode bookmarklet", async () => { + const code = `javascript:(function()%7Balert('hello%20world')%3B%7D)()%3B`; + const result = await webcrack(code); + expect(result.code).toMatchInlineSnapshot(` + "(function () { + alert(\\"hello world\\"); + })();" + `); +}); + +describe(jsx, (expectJS) => { + test("tag name type", () => + expectJS('React.createElement("div", null);').toMatchInlineSnapshot( + "
    ;", + )); + + test("component type", () => + expectJS("React.createElement(TodoList, null);").toMatchInlineSnapshot( + ";", + )); + + test("deeply nested member expression type", () => + expectJS( + "React.createElement(components.list.TodoList, null);", + ).toMatchInlineSnapshot(";")); + + test("rename component with conflicting name", () => + expectJS("function a(){} React.createElement(a, null);") + .toMatchInlineSnapshot(` + function _Component() {} + <_Component />; + `)); + + test("attributes", () => + expectJS( + 'React.createElement("div", { "data-hover": "tooltip", style: { display: "block" } });', + ).toMatchInlineSnapshot(` +
    ; + `)); + + test("spread attributes", () => + expectJS('React.createElement("div", {...props});').toMatchInlineSnapshot( + "
    ;", + )); + + test("children", () => + expectJS( + 'React.createElement("div", null, React.createElement("span", null, "Hello ", name));', + ).toMatchInlineSnapshot("
    Hello {name}
    ;")); + + test("fragment", () => + expectJS( + 'React.createElement(React.Fragment, null, React.createElement("span", null), "test");', + ).toMatchInlineSnapshot("<>test;")); + + test("fragment with key", () => + expectJS( + "React.createElement(React.Fragment, { key: o })", + ).toMatchInlineSnapshot(";")); +}); + +describe(jsxNew, (expectJS) => { + test("tag name type", () => + expectJS('jsx("div", {});').toMatchInlineSnapshot("
    ;")); + + test("component type", () => + expectJS("jsx(TodoList, {});").toMatchInlineSnapshot(";")); + + test("deeply nested member expression type", () => + expectJS("jsx(components.list.TodoList, {});").toMatchInlineSnapshot( + ";", + )); + + test("rename component with conflicting name", () => + expectJS("function a(){} jsx(a, {});").toMatchInlineSnapshot(` + function _Component() {} + <_Component />; + `)); + + test("attributes", () => + expectJS( + 'jsx("div", { "data-hover": "tooltip", style: { display: "block" } });', + ).toMatchInlineSnapshot(` +
    ; + `)); + + test("spread attributes", () => + expectJS('jsx("div", {...props});').toMatchInlineSnapshot( + "
    ;", + )); + + test("children", () => + expectJS( + 'jsx("div", { children: jsxs("span", { children: ["Hello ", name ] }) });', + ).toMatchInlineSnapshot("
    Hello {name}
    ;")); + + test("component with key", () => + expectJS('jsx("div", {}, "test")').toMatchInlineSnapshot( + '
    ;', + )); + + test("array expression child", () => + expectJS('jsx("div", { children: [1] })').toMatchInlineSnapshot( + "
    {[1]}
    ;", + )); + + test("fragment", () => + expectJS( + 'jsxs(React.Fragment, { children: [jsx("span", {}), "test"] });', + ).toMatchInlineSnapshot("<>test;")); + + test("fragment with key", () => + expectJS("jsx(React.Fragment, {}, o)").toMatchInlineSnapshot( + ";", + )); +}); diff --git a/packages/webcrack/tsconfig.build.json b/packages/webcrack/tsconfig.build.json new file mode 100644 index 00000000..4516dc44 --- /dev/null +++ b/packages/webcrack/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + "extends": "@webcrack/typescript-config/base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "emitDeclarationOnly": true + }, + "include": [ + "src" + ] +} diff --git a/packages/webcrack/tsconfig.json b/packages/webcrack/tsconfig.json new file mode 100644 index 00000000..72e1ad1f --- /dev/null +++ b/packages/webcrack/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@webcrack/typescript-config/base.json", + "compilerOptions": { + "noEmit": true + }, + "include": [ + "src", + "test", + ] +} diff --git a/packages/webcrack/vitest.config.ts b/packages/webcrack/vitest.config.ts new file mode 100644 index 00000000..cd893d71 --- /dev/null +++ b/packages/webcrack/vitest.config.ts @@ -0,0 +1,11 @@ +import { join } from "node:path"; +import { defineProject } from "vitest/config"; + +export default defineProject({ + test: { + root: join(__dirname, "test"), + setupFiles: "setup.ts", + include: ["**/*.test.ts"], + isolate: false, + }, +}); diff --git a/patches/vite-plugin-monaco-editor@1.1.0.patch b/patches/vite-plugin-monaco-editor@1.1.0.patch new file mode 100644 index 00000000..64124992 --- /dev/null +++ b/patches/vite-plugin-monaco-editor@1.1.0.patch @@ -0,0 +1,12 @@ +diff --git a/dist/index.js b/dist/index.js +index 2ac6a0430a9e8d970d2e2fadf95401b368c6002f..c6f7456d1c65c2aef4f964b7eae9e15b9de78114 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -102,6 +102,7 @@ function monacoEditorPlugin(options) { + esbuild.buildSync({ + entryPoints: [resolveMonacoPath(work.entry)], + bundle: true, ++ minify: true, + outfile: workerMiddleware_1.cacheDir + workerMiddleware_1.getFilenameByEntry(work.entry), + }); + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..0a1d09c3 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4942 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +patchedDependencies: + vite-plugin-monaco-editor@1.1.0: + hash: ml6vuvpbq2picjecjfyjy32u4e + path: patches/vite-plugin-monaco-editor@1.1.0.patch + +importers: + + .: + devDependencies: + '@webcrack/eslint-config': + specifier: workspace:* + version: link:packages/config-eslint + eslint: + specifier: ^8.54.0 + version: 8.54.0 + prettier: + specifier: ^3.1.0 + version: 3.1.0 + turbo: + specifier: ^1.10.16 + version: 1.10.16 + vitest: + specifier: ^0.34.6 + version: 0.34.6 + + apps/docs: + devDependencies: + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../../packages/config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../../packages/config-typescript + typescript: + specifier: ^5.3.2 + version: 5.3.2 + vitepress: + specifier: 1.0.0-rc.31 + version: 1.0.0-rc.31(@algolia/client-search@4.20.0)(search-insights@2.11.0)(typescript@5.3.2) + + apps/playground: + dependencies: + '@babel/generator': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/types': + specifier: ^7.23.5 + version: 7.23.5 + monaco-editor: + specifier: ^0.44.0 + version: 0.44.0 + sandybox: + specifier: ^1.1.2 + version: 1.1.2 + solid-js: + specifier: ^1.8.6 + version: 1.8.6 + webcrack: + specifier: workspace:* + version: link:../../packages/webcrack + devDependencies: + '@types/babel__generator': + specifier: ^7.6.7 + version: 7.6.7 + '@types/node': + specifier: ^20.10.1 + version: 20.10.1 + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../../packages/config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../../packages/config-typescript + autoprefixer: + specifier: ^10.4.16 + version: 10.4.16(postcss@8.4.31) + daisyui: + specifier: ^4.4.17 + version: 4.4.17(postcss@8.4.31) + postcss: + specifier: ^8.4.31 + version: 8.4.31 + tailwindcss: + specifier: ^3.3.5 + version: 3.3.5 + typescript: + specifier: ^5.3.2 + version: 5.3.2 + vite: + specifier: ^4.5.0 + version: 4.5.0(@types/node@20.10.1) + vite-plugin-monaco-editor: + specifier: ^1.1.0 + version: 1.1.0(patch_hash=ml6vuvpbq2picjecjfyjy32u4e)(monaco-editor@0.44.0) + vite-plugin-node-polyfills: + specifier: ^0.16.0 + version: 0.16.0(vite@4.5.0) + vite-plugin-solid: + specifier: ^2.7.2 + version: 2.7.2(solid-js@1.8.6)(vite@4.5.0) + + apps/web: + dependencies: + docs: + specifier: workspace:* + version: link:../docs + playground: + specifier: workspace:* + version: link:../playground + + packages/ast-utils: + dependencies: + '@babel/generator': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/helper-validator-identifier': + specifier: ^7.22.20 + version: 7.22.20 + '@babel/parser': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/template': + specifier: ^7.22.15 + version: 7.22.15 + '@babel/traverse': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/types': + specifier: ^7.23.5 + version: 7.23.5 + '@codemod/matchers': + specifier: ^1.7.0 + version: 1.7.0 + devDependencies: + '@types/babel__generator': + specifier: ^7.6.7 + version: 7.6.7 + '@types/babel__helper-validator-identifier': + specifier: ^7.15.2 + version: 7.15.2 + '@types/babel__template': + specifier: ^7.4.4 + version: 7.4.4 + '@types/babel__traverse': + specifier: ^7.20.4 + version: 7.20.4 + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../config-typescript + typescript: + specifier: ^5.3.2 + version: 5.3.2 + + packages/config-eslint: + dependencies: + '@typescript-eslint/eslint-plugin': + specifier: ^6.13.1 + version: 6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/parser': + specifier: ^6.13.1 + version: 6.13.1(eslint@8.54.0)(typescript@5.3.2) + eslint-config-prettier: + specifier: ^9.0.0 + version: 9.0.0(eslint@8.54.0) + + packages/config-typescript: {} + + packages/deobfuscate: + dependencies: + '@babel/helper-validator-identifier': + specifier: ^7.22.20 + version: 7.22.20 + '@babel/parser': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/template': + specifier: ^7.22.15 + version: 7.22.15 + '@babel/traverse': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/types': + specifier: ^7.23.5 + version: 7.23.5 + '@codemod/matchers': + specifier: ^1.7.0 + version: 1.7.0 + '@webcrack/ast-utils': + specifier: workspace:* + version: link:../ast-utils + isolated-vm: + specifier: ^4.6.0 + version: 4.6.0 + devDependencies: + '@types/babel__generator': + specifier: ^7.6.7 + version: 7.6.7 + '@types/babel__helper-validator-identifier': + specifier: ^7.15.2 + version: 7.15.2 + '@types/babel__template': + specifier: ^7.4.4 + version: 7.4.4 + '@types/babel__traverse': + specifier: ^7.20.4 + version: 7.20.4 + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../config-typescript + typescript: + specifier: ^5.3.2 + version: 5.3.2 + + packages/unminify: + dependencies: + '@babel/helper-validator-identifier': + specifier: ^7.22.20 + version: 7.22.20 + '@babel/parser': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/template': + specifier: ^7.22.15 + version: 7.22.15 + '@babel/traverse': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/types': + specifier: ^7.23.5 + version: 7.23.5 + '@codemod/matchers': + specifier: ^1.7.0 + version: 1.7.0 + '@webcrack/ast-utils': + specifier: workspace:* + version: link:../ast-utils + devDependencies: + '@types/babel__generator': + specifier: ^7.6.7 + version: 7.6.7 + '@types/babel__helper-validator-identifier': + specifier: ^7.15.2 + version: 7.15.2 + '@types/babel__template': + specifier: ^7.4.4 + version: 7.4.4 + '@types/babel__traverse': + specifier: ^7.20.4 + version: 7.20.4 + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../config-typescript + typescript: + specifier: ^5.3.2 + version: 5.3.2 + + packages/unpack: + dependencies: + '@babel/helper-validator-identifier': + specifier: ^7.22.20 + version: 7.22.20 + '@babel/parser': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/template': + specifier: ^7.22.15 + version: 7.22.15 + '@babel/traverse': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/types': + specifier: ^7.23.5 + version: 7.23.5 + '@codemod/matchers': + specifier: ^1.7.0 + version: 1.7.0 + '@webcrack/ast-utils': + specifier: workspace:* + version: link:../ast-utils + devDependencies: + '@types/babel__generator': + specifier: ^7.6.7 + version: 7.6.7 + '@types/babel__helper-validator-identifier': + specifier: ^7.15.2 + version: 7.15.2 + '@types/babel__template': + specifier: ^7.4.4 + version: 7.4.4 + '@types/babel__traverse': + specifier: ^7.20.4 + version: 7.20.4 + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../config-typescript + typescript: + specifier: ^5.3.2 + version: 5.3.2 + + packages/webcrack: + dependencies: + '@babel/helper-validator-identifier': + specifier: ^7.22.20 + version: 7.22.20 + '@babel/parser': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/template': + specifier: ^7.22.15 + version: 7.22.15 + '@babel/traverse': + specifier: ^7.23.5 + version: 7.23.5 + '@babel/types': + specifier: ^7.23.5 + version: 7.23.5 + '@codemod/matchers': + specifier: ^1.7.0 + version: 1.7.0 + '@webcrack/ast-utils': + specifier: workspace:* + version: link:../ast-utils + '@webcrack/deobfuscate': + specifier: workspace:* + version: link:../deobfuscate + '@webcrack/unminify': + specifier: workspace:* + version: link:../unminify + '@webcrack/unpack': + specifier: workspace:* + version: link:../unpack + babel-plugin-minify-mangle-names: + specifier: ^0.5.1 + version: 0.5.1 + commander: + specifier: ^11.1.0 + version: 11.1.0 + debug: + specifier: ^4.3.4 + version: 4.3.4 + devDependencies: + '@types/babel__generator': + specifier: ^7.6.7 + version: 7.6.7 + '@types/babel__helper-validator-identifier': + specifier: ^7.15.2 + version: 7.15.2 + '@types/babel__template': + specifier: ^7.4.4 + version: 7.4.4 + '@types/babel__traverse': + specifier: ^7.20.4 + version: 7.20.4 + '@types/debug': + specifier: ^4.1.12 + version: 4.1.12 + '@types/node': + specifier: ^20.10.1 + version: 20.10.1 + '@webcrack/eslint-config': + specifier: workspace:* + version: link:../config-eslint + '@webcrack/typescript-config': + specifier: workspace:* + version: link:../config-typescript + esbuild: + specifier: ^0.19.8 + version: 0.19.8 + typescript: + specifier: ^5.3.2 + version: 5.3.2 + +packages: + + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + + /@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0): + resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} + dependencies: + '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0) + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0) + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + - search-insights + dev: true + + /@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0): + resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==} + peerDependencies: + search-insights: '>= 1 < 3' + dependencies: + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0) + search-insights: 2.11.0 + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + dev: true + + /@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0): + resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + dependencies: + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0) + '@algolia/client-search': 4.20.0 + algoliasearch: 4.20.0 + dev: true + + /@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0): + resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + dependencies: + '@algolia/client-search': 4.20.0 + algoliasearch: 4.20.0 + dev: true + + /@algolia/cache-browser-local-storage@4.20.0: + resolution: {integrity: sha512-uujahcBt4DxduBTvYdwO3sBfHuJvJokiC3BP1+O70fglmE1ShkH8lpXqZBac1rrU3FnNYSUs4pL9lBdTKeRPOQ==} + dependencies: + '@algolia/cache-common': 4.20.0 + dev: true + + /@algolia/cache-common@4.20.0: + resolution: {integrity: sha512-vCfxauaZutL3NImzB2G9LjLt36vKAckc6DhMp05An14kVo8F1Yofb6SIl6U3SaEz8pG2QOB9ptwM5c+zGevwIQ==} + dev: true + + /@algolia/cache-in-memory@4.20.0: + resolution: {integrity: sha512-Wm9ak/IaacAZXS4mB3+qF/KCoVSBV6aLgIGFEtQtJwjv64g4ePMapORGmCyulCFwfePaRAtcaTbMcJF+voc/bg==} + dependencies: + '@algolia/cache-common': 4.20.0 + dev: true + + /@algolia/client-account@4.20.0: + resolution: {integrity: sha512-GGToLQvrwo7am4zVkZTnKa72pheQeez/16sURDWm7Seyz+HUxKi3BM6fthVVPUEBhtJ0reyVtuK9ArmnaKl10Q==} + dependencies: + '@algolia/client-common': 4.20.0 + '@algolia/client-search': 4.20.0 + '@algolia/transporter': 4.20.0 + dev: true + + /@algolia/client-analytics@4.20.0: + resolution: {integrity: sha512-EIr+PdFMOallRdBTHHdKI3CstslgLORQG7844Mq84ib5oVFRVASuuPmG4bXBgiDbcsMLUeOC6zRVJhv1KWI0ug==} + dependencies: + '@algolia/client-common': 4.20.0 + '@algolia/client-search': 4.20.0 + '@algolia/requester-common': 4.20.0 + '@algolia/transporter': 4.20.0 + dev: true + + /@algolia/client-common@4.20.0: + resolution: {integrity: sha512-P3WgMdEss915p+knMMSd/fwiHRHKvDu4DYRrCRaBrsfFw7EQHon+EbRSm4QisS9NYdxbS04kcvNoavVGthyfqQ==} + dependencies: + '@algolia/requester-common': 4.20.0 + '@algolia/transporter': 4.20.0 + dev: true + + /@algolia/client-personalization@4.20.0: + resolution: {integrity: sha512-N9+zx0tWOQsLc3K4PVRDV8GUeOLAY0i445En79Pr3zWB+m67V+n/8w4Kw1C5LlbHDDJcyhMMIlqezh6BEk7xAQ==} + dependencies: + '@algolia/client-common': 4.20.0 + '@algolia/requester-common': 4.20.0 + '@algolia/transporter': 4.20.0 + dev: true + + /@algolia/client-search@4.20.0: + resolution: {integrity: sha512-zgwqnMvhWLdpzKTpd3sGmMlr4c+iS7eyyLGiaO51zDZWGMkpgoNVmltkzdBwxOVXz0RsFMznIxB9zuarUv4TZg==} + dependencies: + '@algolia/client-common': 4.20.0 + '@algolia/requester-common': 4.20.0 + '@algolia/transporter': 4.20.0 + dev: true + + /@algolia/logger-common@4.20.0: + resolution: {integrity: sha512-xouigCMB5WJYEwvoWW5XDv7Z9f0A8VoXJc3VKwlHJw/je+3p2RcDXfksLI4G4lIVncFUYMZx30tP/rsdlvvzHQ==} + dev: true + + /@algolia/logger-console@4.20.0: + resolution: {integrity: sha512-THlIGG1g/FS63z0StQqDhT6bprUczBI8wnLT3JWvfAQDZX5P6fCg7dG+pIrUBpDIHGszgkqYEqECaKKsdNKOUA==} + dependencies: + '@algolia/logger-common': 4.20.0 + dev: true + + /@algolia/requester-browser-xhr@4.20.0: + resolution: {integrity: sha512-HbzoSjcjuUmYOkcHECkVTwAelmvTlgs48N6Owt4FnTOQdwn0b8pdht9eMgishvk8+F8bal354nhx/xOoTfwiAw==} + dependencies: + '@algolia/requester-common': 4.20.0 + dev: true + + /@algolia/requester-common@4.20.0: + resolution: {integrity: sha512-9h6ye6RY/BkfmeJp7Z8gyyeMrmmWsMOCRBXQDs4mZKKsyVlfIVICpcSibbeYcuUdurLhIlrOUkH3rQEgZzonng==} + dev: true + + /@algolia/requester-node-http@4.20.0: + resolution: {integrity: sha512-ocJ66L60ABSSTRFnCHIEZpNHv6qTxsBwJEPfYaSBsLQodm0F9ptvalFkHMpvj5DfE22oZrcrLbOYM2bdPJRHng==} + dependencies: + '@algolia/requester-common': 4.20.0 + dev: true + + /@algolia/transporter@4.20.0: + resolution: {integrity: sha512-Lsii1pGWOAISbzeyuf+r/GPhvHMPHSPrTDWNcIzOE1SG1inlJHICaVe2ikuoRjcpgxZNU54Jl+if15SUCsaTUg==} + dependencies: + '@algolia/cache-common': 4.20.0 + '@algolia/logger-common': 4.20.0 + '@algolia/requester-common': 4.20.0 + dev: true + + /@alloc/quick-lru@5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + + /@babel/code-frame@7.23.4: + resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + + /@babel/compat-data@7.23.3: + resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==} + engines: {node: '>=6.9.0'} + + /@babel/core@7.23.3: + resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.4 + '@babel/generator': 7.23.5 + '@babel/helper-compilation-targets': 7.22.15 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) + '@babel/helpers': 7.23.4 + '@babel/parser': 7.23.5 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + /@babel/generator@7.23.5: + resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + + /@babel/helper-annotate-as-pure@7.22.5: + resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-compilation-targets@7.22.15: + resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.3 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.22.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + /@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.23.3): + resolution: {integrity: sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.3) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.5 + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + + /@babel/helper-member-expression-to-functions@7.23.0: + resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-module-imports@7.18.6: + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + + /@babel/helper-optimise-call-expression@7.22.5: + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.3): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.5 + + /@babel/helper-string-parser@7.23.4: + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.22.15: + resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} + engines: {node: '>=6.9.0'} + + /@babel/helpers@7.23.4: + resolution: {integrity: sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.5 + '@babel/types': 7.23.5 + transitivePeerDependencies: + - supports-color + + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/parser@7.23.5: + resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.5 + + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + dev: true + + /@babel/plugin-transform-typescript@7.23.4(@babel/core@7.23.3): + resolution: {integrity: sha512-39hCCOl+YUAyMOu6B9SmUTiHUU0t/CxJNUmY3qRdJujbqi+lrQcL11ysYUsAvFWPBdhihrv1z0oRG84Yr3dODQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.23.3) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.3) + dev: true + + /@babel/preset-typescript@7.23.3(@babel/core@7.23.3): + resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.22.15 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.3) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.3) + '@babel/plugin-transform-typescript': 7.23.4(@babel/core@7.23.3) + dev: true + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.4 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 + + /@babel/traverse@7.23.5: + resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + /@babel/types@7.23.5: + resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + /@codemod/matchers@1.7.0: + resolution: {integrity: sha512-edfMWz/eckYmtpXuW6JINnWa81eKJ555KX+nn7gUoxQFI5qFY59DIsvZmhACOUpcYAFpF2rT8I7tiLgmZ1zMYQ==} + dependencies: + '@babel/types': 7.23.5 + '@codemod/utils': 1.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@codemod/parser@1.4.1: + resolution: {integrity: sha512-w9bvtcC1oJTuXAnp+ZOYLOWagtb8UBBZEKp9fYI0dA5KARiUJf00MmtDQyULaeZj/AQAGuOrm739DFDLeHv+0g==} + dependencies: + '@babel/parser': 7.23.5 + dev: false + + /@codemod/utils@1.1.0: + resolution: {integrity: sha512-Zx6A4xDifEqL0s9ejh62/mQmDXje+E62zYHGiGfRHzVhzmA41pDFZW/m7Hl9+fmbODJxlg9ElMsjHdhasSm7TA==} + dependencies: + '@babel/core': 7.23.3 + '@babel/types': 7.23.5 + '@codemod/parser': 1.4.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@docsearch/css@3.5.2: + resolution: {integrity: sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==} + dev: true + + /@docsearch/js@3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0): + resolution: {integrity: sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg==} + dependencies: + '@docsearch/react': 3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0) + preact: 10.19.2 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/react' + - react + - react-dom + - search-insights + dev: true + + /@docsearch/react@3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0): + resolution: {integrity: sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==} + peerDependencies: + '@types/react': '>= 16.8.0 < 19.0.0' + react: '>= 16.8.0 < 19.0.0' + react-dom: '>= 16.8.0 < 19.0.0' + search-insights: '>= 1 < 3' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + dependencies: + '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0)(search-insights@2.11.0) + '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.20.0) + '@docsearch/css': 3.5.2 + algoliasearch: 4.20.0 + search-insights: 2.11.0 + transitivePeerDependencies: + - '@algolia/client-search' + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.8: + resolution: {integrity: sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.8: + resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.8: + resolution: {integrity: sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.8: + resolution: {integrity: sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.8: + resolution: {integrity: sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.8: + resolution: {integrity: sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.8: + resolution: {integrity: sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.8: + resolution: {integrity: sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.8: + resolution: {integrity: sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.8: + resolution: {integrity: sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.8: + resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.8: + resolution: {integrity: sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.8: + resolution: {integrity: sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.8: + resolution: {integrity: sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.8: + resolution: {integrity: sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.8: + resolution: {integrity: sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.8: + resolution: {integrity: sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.8: + resolution: {integrity: sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.8: + resolution: {integrity: sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.8: + resolution: {integrity: sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.8: + resolution: {integrity: sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.8: + resolution: {integrity: sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.54.0 + eslint-visitor-keys: 3.4.3 + + /@eslint-community/regexpp@4.10.0: + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + /@eslint/eslintrc@2.1.3: + resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.23.0 + ignore: 5.3.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + /@eslint/js@8.54.0: + resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + /@humanwhocodes/config-array@0.11.13: + resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 2.0.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + /@humanwhocodes/object-schema@2.0.1: + resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + + /@jest/schemas@29.6.3: + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.20 + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + /@jridgewell/trace-mapping@0.3.20: + resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + + /@rollup/plugin-inject@5.0.5: + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.5 + estree-walker: 2.0.2 + magic-string: 0.30.5 + dev: true + + /@rollup/pluginutils@5.0.5: + resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: true + + /@rollup/rollup-android-arm-eabi@4.5.2: + resolution: {integrity: sha512-ee7BudTwwrglFYSc3UnqInDDjCLWHKrFmGNi4aK7jlEyg4CyPa1DCMrZfsN1O13YT76UFEqXz2CoN7BCGpUlJw==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.5.2: + resolution: {integrity: sha512-xOuhj9HHtn8128ir8veoQsBbAUBasDbHIBniYTEx02pAmu9EXL+ZjJqngnNEy6ZgZ4h1JwL33GMNu3yJL5Mzow==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.5.2: + resolution: {integrity: sha512-NTGJWoL8bKyqyWFn9/RzSv4hQ4wTbaAv0lHHRwf4OnpiiP4P8W0jiXbm8Nc5BCXKmWAwuvJY82mcIU2TayC20g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.5.2: + resolution: {integrity: sha512-hlKqj7bpPvU15sZo4za14u185lpMzdwWLMc9raMqPK4wywt0wR23y1CaVQ4oAFXat3b5/gmRntyfpwWTKl+vvA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.5.2: + resolution: {integrity: sha512-7ZIZx8c3u+pfI0ohQsft/GywrXez0uR6dUP0JhBuCK3sFO5TfdLn/YApnVkvPxuTv3+YKPIZend9Mt7Cz6sS3Q==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.5.2: + resolution: {integrity: sha512-7Pk/5mO11JW/cH+a8lL/i0ZxmRGrbpYqN0VwO2DHhU+SJWWOH2zE1RAcPaj8KqiwC8DCDIJOSxjV9+9lLb6aeA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.5.2: + resolution: {integrity: sha512-KrRnuG5phJx756e62wxvWH2e+TK84MP2IVuPwfge+GBvWqIUfVzFRn09TKruuQBXzZp52Vyma7FjMDkwlA9xpg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.5.2: + resolution: {integrity: sha512-My+53GasPa2D2tU5dXiyHYwrELAUouSfkNlZ3bUKpI7btaztO5vpALEs3mvFjM7aKTvEbc7GQckuXeXIDKQ0fg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.5.2: + resolution: {integrity: sha512-/f0Q6Sc+Vw54Ws6N8fxaEe4R7at3b8pFyv+O/F2VaQ4hODUJcRUcCBJh6zuqtgQQt7w845VTkGLFgWZkP3tUoQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.5.2: + resolution: {integrity: sha512-NCKuuZWLht6zj7s6EIFef4BxCRX1GMr83S2W4HPCA0RnJ4iHE4FS1695q6Ewoa6A9nFjJe1//yUu0kgBU07Edw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.5.2: + resolution: {integrity: sha512-J5zL3riR4AOyU/J3M/i4k/zZ8eP1yT+nTmAKztCXJtnI36jYH0eepvob22mAQ/kLwfsK2TB6dbyVY1F8c/0H5A==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.5.2: + resolution: {integrity: sha512-pL0RXRHuuGLhvs7ayX/SAHph1hrDPXOM5anyYUQXWJEENxw3nfHkzv8FfVlEVcLyKPAEgDRkd6RKZq2SMqS/yg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 + '@types/babel__generator': 7.6.7 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.4 + dev: true + + /@types/babel__generator@7.6.7: + resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@types/babel__helper-validator-identifier@7.15.2: + resolution: {integrity: sha512-l3dkwCt890NFhMwPKXbxsWXC0Por0/+KaFIiQP1j38/vWSH2P3Tn6m+IuJHkx2SBI3VLFqincFe9JtBk2NFHOw==} + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.23.5 + '@babel/types': 7.23.5 + dev: true + + /@types/babel__traverse@7.20.4: + resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} + dependencies: + '@babel/types': 7.23.5 + dev: true + + /@types/chai-subset@1.3.5: + resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==} + dependencies: + '@types/chai': 4.3.11 + dev: true + + /@types/chai@4.3.11: + resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==} + dev: true + + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 0.7.34 + dev: true + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true + + /@types/hast@3.0.3: + resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==} + dependencies: + '@types/unist': 3.0.2 + dev: true + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: false + + /@types/linkify-it@3.0.5: + resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} + dev: true + + /@types/markdown-it@13.0.7: + resolution: {integrity: sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==} + dependencies: + '@types/linkify-it': 3.0.5 + '@types/mdurl': 1.0.5 + dev: true + + /@types/mdast@4.0.3: + resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==} + dependencies: + '@types/unist': 3.0.2 + dev: true + + /@types/mdurl@1.0.5: + resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + dev: true + + /@types/ms@0.7.34: + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + dev: true + + /@types/node@20.10.1: + resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/semver@7.5.6: + resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} + dev: false + + /@types/unist@3.0.2: + resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + dev: true + + /@types/web-bluetooth@0.0.20: + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + dev: true + + /@typescript-eslint/eslint-plugin@6.13.1(@typescript-eslint/parser@6.13.1)(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 6.13.1(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/scope-manager': 6.13.1 + '@typescript-eslint/type-utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.13.1 + debug: 4.3.4 + eslint: 8.54.0 + graphemer: 1.4.0 + ignore: 5.3.0 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.3.2) + typescript: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/parser@6.13.1(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.13.1 + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + '@typescript-eslint/visitor-keys': 6.13.1 + debug: 4.3.4 + eslint: 8.54.0 + typescript: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/scope-manager@6.13.1: + resolution: {integrity: sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/visitor-keys': 6.13.1 + dev: false + + /@typescript-eslint/type-utils@6.13.1(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + '@typescript-eslint/utils': 6.13.1(eslint@8.54.0)(typescript@5.3.2) + debug: 4.3.4 + eslint: 8.54.0 + ts-api-utils: 1.0.3(typescript@5.3.2) + typescript: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/types@6.13.1: + resolution: {integrity: sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: false + + /@typescript-eslint/typescript-estree@6.13.1(typescript@5.3.2): + resolution: {integrity: sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/visitor-keys': 6.13.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.3.2) + typescript: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/utils@6.13.1(eslint@8.54.0)(typescript@5.3.2): + resolution: {integrity: sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.6 + '@typescript-eslint/scope-manager': 6.13.1 + '@typescript-eslint/types': 6.13.1 + '@typescript-eslint/typescript-estree': 6.13.1(typescript@5.3.2) + eslint: 8.54.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: false + + /@typescript-eslint/visitor-keys@6.13.1: + resolution: {integrity: sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.13.1 + eslint-visitor-keys: 3.4.3 + dev: false + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + /@vitejs/plugin-vue@4.5.0(vite@5.0.2)(vue@3.3.9): + resolution: {integrity: sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 || ^5.0.0 + vue: ^3.2.25 + dependencies: + vite: 5.0.2(@types/node@20.10.1) + vue: 3.3.9(typescript@5.3.2) + dev: true + + /@vitest/expect@0.34.6: + resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==} + dependencies: + '@vitest/spy': 0.34.6 + '@vitest/utils': 0.34.6 + chai: 4.3.10 + dev: true + + /@vitest/runner@0.34.6: + resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==} + dependencies: + '@vitest/utils': 0.34.6 + p-limit: 4.0.0 + pathe: 1.1.1 + dev: true + + /@vitest/snapshot@0.34.6: + resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==} + dependencies: + magic-string: 0.30.5 + pathe: 1.1.1 + pretty-format: 29.7.0 + dev: true + + /@vitest/spy@0.34.6: + resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==} + dependencies: + tinyspy: 2.2.0 + dev: true + + /@vitest/utils@0.34.6: + resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==} + dependencies: + diff-sequences: 29.6.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + dev: true + + /@vue/compiler-core@3.3.9: + resolution: {integrity: sha512-+/Lf68Vr/nFBA6ol4xOtJrW+BQWv3QWKfRwGSm70jtXwfhZNF4R/eRgyVJYoxFRhdCTk/F6g99BP0ffPgZihfQ==} + dependencies: + '@babel/parser': 7.23.5 + '@vue/shared': 3.3.9 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + dev: true + + /@vue/compiler-dom@3.3.9: + resolution: {integrity: sha512-nfWubTtLXuT4iBeDSZ5J3m218MjOy42Vp2pmKVuBKo2/BLcrFUX8nCSr/bKRFiJ32R8qbdnnnBgRn9AdU5v0Sg==} + dependencies: + '@vue/compiler-core': 3.3.9 + '@vue/shared': 3.3.9 + dev: true + + /@vue/compiler-sfc@3.3.9: + resolution: {integrity: sha512-wy0CNc8z4ihoDzjASCOCsQuzW0A/HP27+0MDSSICMjVIFzk/rFViezkR3dzH+miS2NDEz8ywMdbjO5ylhOLI2A==} + dependencies: + '@babel/parser': 7.23.5 + '@vue/compiler-core': 3.3.9 + '@vue/compiler-dom': 3.3.9 + '@vue/compiler-ssr': 3.3.9 + '@vue/reactivity-transform': 3.3.9 + '@vue/shared': 3.3.9 + estree-walker: 2.0.2 + magic-string: 0.30.5 + postcss: 8.4.31 + source-map-js: 1.0.2 + dev: true + + /@vue/compiler-ssr@3.3.9: + resolution: {integrity: sha512-NO5oobAw78R0G4SODY5A502MGnDNiDjf6qvhn7zD7TJGc8XDeIEw4fg6JU705jZ/YhuokBKz0A5a/FL/XZU73g==} + dependencies: + '@vue/compiler-dom': 3.3.9 + '@vue/shared': 3.3.9 + dev: true + + /@vue/devtools-api@6.5.1: + resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} + dev: true + + /@vue/reactivity-transform@3.3.9: + resolution: {integrity: sha512-HnUFm7Ry6dFa4Lp63DAxTixUp8opMtQr6RxQCpDI1vlh12rkGIeYqMvJtK+IKyEfEOa2I9oCkD1mmsPdaGpdVg==} + dependencies: + '@babel/parser': 7.23.5 + '@vue/compiler-core': 3.3.9 + '@vue/shared': 3.3.9 + estree-walker: 2.0.2 + magic-string: 0.30.5 + dev: true + + /@vue/reactivity@3.3.9: + resolution: {integrity: sha512-VmpIqlNp+aYDg2X0xQhJqHx9YguOmz2UxuUJDckBdQCNkipJvfk9yA75woLWElCa0Jtyec3lAAt49GO0izsphw==} + dependencies: + '@vue/shared': 3.3.9 + dev: true + + /@vue/runtime-core@3.3.9: + resolution: {integrity: sha512-xxaG9KvPm3GTRuM4ZyU8Tc+pMVzcu6eeoSRQJ9IE7NmCcClW6z4B3Ij6L4EDl80sxe/arTtQ6YmgiO4UZqRc+w==} + dependencies: + '@vue/reactivity': 3.3.9 + '@vue/shared': 3.3.9 + dev: true + + /@vue/runtime-dom@3.3.9: + resolution: {integrity: sha512-e7LIfcxYSWbV6BK1wQv9qJyxprC75EvSqF/kQKe6bdZEDNValzeRXEVgiX7AHI6hZ59HA4h7WT5CGvm69vzJTQ==} + dependencies: + '@vue/runtime-core': 3.3.9 + '@vue/shared': 3.3.9 + csstype: 3.1.2 + dev: true + + /@vue/server-renderer@3.3.9(vue@3.3.9): + resolution: {integrity: sha512-w0zT/s5l3Oa3ZjtLW88eO4uV6AQFqU8X5GOgzq7SkQQu6vVr+8tfm+OI2kDBplS/W/XgCBuFXiPw6T5EdwXP0A==} + peerDependencies: + vue: 3.3.9 + dependencies: + '@vue/compiler-ssr': 3.3.9 + '@vue/shared': 3.3.9 + vue: 3.3.9(typescript@5.3.2) + dev: true + + /@vue/shared@3.3.9: + resolution: {integrity: sha512-ZE0VTIR0LmYgeyhurPTpy4KzKsuDyQbMSdM49eKkMnT5X4VfFBLysMzjIZhLEFQYjjOVVfbvUDHckwjDFiO2eA==} + dev: true + + /@vueuse/core@10.6.1(vue@3.3.9): + resolution: {integrity: sha512-Pc26IJbqgC9VG1u6VY/xrXXfxD33hnvxBnKrLlA2LJlyHII+BSrRoTPJgGYq7qZOu61itITFUnm6QbacwZ4H8Q==} + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.6.1 + '@vueuse/shared': 10.6.1(vue@3.3.9) + vue-demi: 0.14.6(vue@3.3.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /@vueuse/integrations@10.6.1(focus-trap@7.5.4)(vue@3.3.9): + resolution: {integrity: sha512-mPDupuofMJ4DPmtX/FfP1MajmWRzYDv8WSaTCo8LQ5kFznjWgmUQ16ApjYqgMquqffNY6+IRMdMgosLDRZOSZA==} + peerDependencies: + async-validator: '*' + axios: '*' + change-case: '*' + drauu: '*' + focus-trap: '*' + fuse.js: '*' + idb-keyval: '*' + jwt-decode: '*' + nprogress: '*' + qrcode: '*' + sortablejs: '*' + universal-cookie: '*' + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + dependencies: + '@vueuse/core': 10.6.1(vue@3.3.9) + '@vueuse/shared': 10.6.1(vue@3.3.9) + focus-trap: 7.5.4 + vue-demi: 0.14.6(vue@3.3.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /@vueuse/metadata@10.6.1: + resolution: {integrity: sha512-qhdwPI65Bgcj23e5lpGfQsxcy0bMjCAsUGoXkJ7DsoeDUdasbZ2DBa4dinFCOER3lF4gwUv+UD2AlA11zdzMFw==} + dev: true + + /@vueuse/shared@10.6.1(vue@3.3.9): + resolution: {integrity: sha512-TECVDTIedFlL0NUfHWncf3zF9Gc4VfdxfQc8JFwoVZQmxpONhLxFrlm0eHQeidHj4rdTPL3KXJa0TZCk1wnc5Q==} + dependencies: + vue-demi: 0.14.6(vue@3.3.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /acorn-jsx@5.3.2(acorn@8.11.2): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.11.2 + + /acorn-walk@8.3.0: + resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + /algoliasearch@4.20.0: + resolution: {integrity: sha512-y+UHEjnOItoNy0bYO+WWmLWBlPwDjKHW6mNHrPi0NkuhpQOOEbrkwQH/wgKFDLh7qlKjzoKeiRtlpewDPDG23g==} + dependencies: + '@algolia/cache-browser-local-storage': 4.20.0 + '@algolia/cache-common': 4.20.0 + '@algolia/cache-in-memory': 4.20.0 + '@algolia/client-account': 4.20.0 + '@algolia/client-analytics': 4.20.0 + '@algolia/client-common': 4.20.0 + '@algolia/client-personalization': 4.20.0 + '@algolia/client-search': 4.20.0 + '@algolia/logger-common': 4.20.0 + '@algolia/logger-console': 4.20.0 + '@algolia/requester-browser-xhr': 4.20.0 + '@algolia/requester-common': 4.20.0 + '@algolia/requester-node-http': 4.20.0 + '@algolia/transporter': 4.20.0 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: false + + /asn1.js@5.4.1: + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + safer-buffer: 2.1.2 + dev: true + + /assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + dependencies: + call-bind: 1.0.5 + is-nan: 1.3.2 + object-is: 1.1.5 + object.assign: 4.1.4 + util: 0.12.5 + dev: true + + /assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + + /autoprefixer@10.4.16(postcss@8.4.31): + resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.22.1 + caniuse-lite: 1.0.30001564 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.31 + postcss-value-parser: 4.2.0 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + + /babel-helper-mark-eval-scopes@0.4.3: + resolution: {integrity: sha512-+d/mXPP33bhgHkdVOiPkmYoeXJ+rXRWi7OdhwpyseIqOS8CmzHQXHUp/+/Qr8baXsT0kjGpMHHofHs6C3cskdA==} + dev: false + + /babel-plugin-jsx-dom-expressions@0.37.9(@babel/core@7.23.3): + resolution: {integrity: sha512-6w+zs2i14fVanj4e1hXCU5cp+x0U0LJ5jScknpMZZUteHhwFRGJflHMVJ+xAcW7ku41FYjr7DgtK9mnc2SXlJg==} + peerDependencies: + '@babel/core': ^7.20.12 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-module-imports': 7.18.6 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.3) + '@babel/types': 7.23.5 + html-entities: 2.3.3 + validate-html-nesting: 1.2.2 + dev: true + + /babel-plugin-minify-mangle-names@0.5.1: + resolution: {integrity: sha512-8KMichAOae2FHlipjNDTo2wz97MdEb2Q0jrn4NIRXzHH7SJ3c5TaNNBkeTHbk9WUsMnqpNUx949ugM9NFWewzw==} + dependencies: + babel-helper-mark-eval-scopes: 0.4.3 + dev: false + + /babel-preset-solid@1.8.6(@babel/core@7.23.3): + resolution: {integrity: sha512-Ened42CHjU4EFkvNeS042/3Pm21yvMWn8p4G4ddzQTlKaMwSGGD1VciA/e7EshBVHJCcBj9vHiUd/r3A4qLPZA==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + babel-plugin-jsx-dom-expressions: 0.37.9(@babel/core@7.23.3) + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: true + + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + dev: true + + /browser-resolve@2.0.0: + resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} + dependencies: + resolve: 1.22.8 + dev: true + + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + dev: true + + /browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + dependencies: + cipher-base: 1.0.4 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /browserify-rsa@4.1.0: + resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + dev: true + + /browserify-sign@4.2.2: + resolution: {integrity: sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==} + engines: {node: '>= 4'} + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.5.4 + inherits: 2.0.4 + parse-asn1: 5.1.6 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + dev: true + + /browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + dependencies: + pako: 1.0.11 + dev: true + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001564 + electron-to-chromium: 1.4.594 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.22.1) + + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + dev: true + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + dev: true + + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + + /caniuse-lite@1.0.30001564: + resolution: {integrity: sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==} + + /ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + dev: true + + /chai@4.3.10: + resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + /character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + dev: true + + /character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + dev: true + + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + dev: true + + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: false + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + dev: true + + /constants-browserify@1.0.0: + resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + /create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + dependencies: + bn.js: 4.12.0 + elliptic: 6.5.4 + dev: true + + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + dev: true + + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: true + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + /crypto-browserify@3.12.0: + resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.2 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + dev: true + + /css-selector-tokenizer@0.8.0: + resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} + dependencies: + cssesc: 3.0.0 + fastparse: 1.1.2 + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + + /culori@3.3.0: + resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /daisyui@4.4.17(postcss@8.4.31): + resolution: {integrity: sha512-vcxLKoWiqPjEtcBkSayi9sDW1kWgWRdy1GjSu3zNtMiCsXwqDpCzNkdijuY9RuJ/2tBCtnwxhBv72Yizfi7KAQ==} + engines: {node: '>=16.9.0'} + dependencies: + css-selector-tokenizer: 0.8.0 + culori: 3.3.0 + picocolors: 1.0.0 + postcss-js: 4.0.1(postcss@8.4.31) + transitivePeerDependencies: + - postcss + dev: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + + /deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 + dev: true + + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.1 + object-keys: 1.1.1 + dev: true + + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: true + + /des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: true + + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + dev: false + + /devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dependencies: + dequal: 2.0.3 + dev: true + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + + /diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dependencies: + bn.js: 4.12.0 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: false + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + + /domain-browser@4.23.0: + resolution: {integrity: sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==} + engines: {node: '>=10'} + dev: true + + /electron-to-chromium@1.4.594: + resolution: {integrity: sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==} + + /elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: true + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /esbuild@0.19.8: + resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.8 + '@esbuild/android-arm64': 0.19.8 + '@esbuild/android-x64': 0.19.8 + '@esbuild/darwin-arm64': 0.19.8 + '@esbuild/darwin-x64': 0.19.8 + '@esbuild/freebsd-arm64': 0.19.8 + '@esbuild/freebsd-x64': 0.19.8 + '@esbuild/linux-arm': 0.19.8 + '@esbuild/linux-arm64': 0.19.8 + '@esbuild/linux-ia32': 0.19.8 + '@esbuild/linux-loong64': 0.19.8 + '@esbuild/linux-mips64el': 0.19.8 + '@esbuild/linux-ppc64': 0.19.8 + '@esbuild/linux-riscv64': 0.19.8 + '@esbuild/linux-s390x': 0.19.8 + '@esbuild/linux-x64': 0.19.8 + '@esbuild/netbsd-x64': 0.19.8 + '@esbuild/openbsd-x64': 0.19.8 + '@esbuild/sunos-x64': 0.19.8 + '@esbuild/win32-arm64': 0.19.8 + '@esbuild/win32-ia32': 0.19.8 + '@esbuild/win32-x64': 0.19.8 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + /eslint-config-prettier@9.0.0(eslint@8.54.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.54.0 + dev: false + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + /eslint@8.54.0: + resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/eslintrc': 2.1.3 + '@eslint/js': 8.54.0 + '@humanwhocodes/config-array': 0.11.13 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.23.0 + graphemer: 1.4.0 + ignore: 5.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.11.2 + acorn-jsx: 5.3.2(acorn@8.11.2) + eslint-visitor-keys: 3.4.3 + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + dev: true + + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + /fastparse@1.1.2: + resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.2.0 + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.9 + keyv: 4.5.4 + rimraf: 3.0.2 + + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + + /focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + dependencies: + tabbable: 6.2.0 + dev: true + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + dev: true + + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + + /glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + /globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: false + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: true + + /hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + dev: true + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /hast-util-from-parse5@8.0.1: + resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} + dependencies: + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + devlop: 1.1.0 + hastscript: 8.0.0 + property-information: 6.4.0 + vfile: 6.0.1 + vfile-location: 5.0.2 + web-namespaces: 2.0.1 + dev: true + + /hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + dependencies: + '@types/hast': 3.0.3 + dev: true + + /hast-util-raw@9.0.1: + resolution: {integrity: sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==} + dependencies: + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + '@ungap/structured-clone': 1.2.0 + hast-util-from-parse5: 8.0.1 + hast-util-to-parse5: 8.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.0.2 + parse5: 7.1.2 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.1 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + dev: true + + /hast-util-to-html@9.0.0: + resolution: {integrity: sha512-IVGhNgg7vANuUA2XKrT6sOIIPgaYZnmLx3l/CCOAK0PtgfoHrZwX7jCSYyFxHTrGmC6S9q8aQQekjp4JPZF+cw==} + dependencies: + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-raw: 9.0.1 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.0.2 + property-information: 6.4.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.3 + zwitch: 2.0.4 + dev: true + + /hast-util-to-parse5@8.0.0: + resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} + dependencies: + '@types/hast': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 6.4.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + dev: true + + /hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + dependencies: + '@types/hast': 3.0.3 + dev: true + + /hastscript@8.0.0: + resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} + dependencies: + '@types/hast': 3.0.3 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 6.4.0 + space-separated-tokens: 2.0.2 + dev: true + + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: true + + /html-entities@2.3.3: + resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} + dev: true + + /html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + dev: true + + /https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + /ignore@5.3.0: + resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + engines: {node: '>= 4'} + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.13 + dev: true + + /is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /isolated-vm@4.6.0: + resolution: {integrity: sha512-MEnfC/54q5PED3VJ9UJYJPOlU6mYFHS3ivR9E8yeNNBEFRFUNBnY0xO4Rj3D/SOtFKPNmsQp9NWUYSKZqAoZiA==} + engines: {node: '>=16.0.0'} + requiresBuild: true + dependencies: + prebuild-install: 7.1.1 + dev: false + + /isomorphic-timers-promises@1.0.1: + resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} + engines: {node: '>=10'} + dev: true + + /jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + dependencies: + argparse: 2.0.1 + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + /jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lilconfig@3.0.0: + resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} + engines: {node: '>=14'} + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /local-pkg@0.4.3: + resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} + engines: {node: '>=14'} + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + /loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + dependencies: + get-func-name: 2.0.2 + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + + /magic-string@0.30.5: + resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + dev: true + + /md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /mdast-util-to-hast@13.0.2: + resolution: {integrity: sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og==} + dependencies: + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + '@ungap/structured-clone': 1.2.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.0 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + dev: true + + /merge-anything@5.1.7: + resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} + engines: {node: '>=12.13'} + dependencies: + is-what: 4.1.16 + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + /micromark-util-character@2.0.1: + resolution: {integrity: sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==} + dependencies: + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: true + + /micromark-util-encode@2.0.0: + resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + dev: true + + /micromark-util-sanitize-uri@2.0.0: + resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + dependencies: + micromark-util-character: 2.0.1 + micromark-util-encode: 2.0.0 + micromark-util-symbol: 2.0.0 + dev: true + + /micromark-util-symbol@2.0.0: + resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + dev: true + + /micromark-util-types@2.0.0: + resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + /miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + dev: true + + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: true + + /minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: false + + /minisearch@6.3.0: + resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==} + dev: true + + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + + /mlly@1.4.2: + resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} + dependencies: + acorn: 8.11.2 + pathe: 1.1.1 + pkg-types: 1.0.3 + ufo: 1.3.2 + dev: true + + /monaco-editor@0.44.0: + resolution: {integrity: sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==} + + /mrmime@1.0.1: + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + /node-abi@3.51.0: + resolution: {integrity: sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: false + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + + /node-stdlib-browser@1.2.0: + resolution: {integrity: sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg==} + engines: {node: '>=10'} + dependencies: + assert: 2.1.0 + browser-resolve: 2.0.0 + browserify-zlib: 0.2.0 + buffer: 5.7.1 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + create-require: 1.1.1 + crypto-browserify: 3.12.0 + domain-browser: 4.23.0 + events: 3.3.0 + https-browserify: 1.0.0 + isomorphic-timers-promises: 1.0.1 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + pkg-dir: 5.0.0 + process: 0.11.10 + punycode: 1.4.1 + querystring-es3: 0.2.1 + readable-stream: 3.6.2 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + url: 0.11.3 + util: 0.12.5 + vm-browserify: 1.1.2 + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /object-is@1.1.5: + resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + + /os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + + /parse-asn1@5.1.6: + resolution: {integrity: sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==} + dependencies: + asn1.js: 5.4.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + pbkdf2: 3.1.2 + safe-buffer: 5.2.1 + dev: true + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.5.0 + dev: true + + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: false + + /pathe@1.1.1: + resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: true + + /pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /pkg-dir@5.0.0: + resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} + engines: {node: '>=10'} + dependencies: + find-up: 5.0.0 + dev: true + + /pkg-types@1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.4.2 + pathe: 1.1.1 + dev: true + + /postcss-import@15.1.0(postcss@8.4.31): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.31 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + dev: true + + /postcss-js@4.0.1(postcss@8.4.31): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.31 + dev: true + + /postcss-load-config@4.0.2(postcss@8.4.31): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.0.0 + postcss: 8.4.31 + yaml: 2.3.4 + dev: true + + /postcss-nested@6.0.1(postcss@8.4.31): + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.31 + postcss-selector-parser: 6.0.13 + dev: true + + /postcss-selector-parser@6.0.13: + resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /preact@10.19.2: + resolution: {integrity: sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg==} + dev: true + + /prebuild-install@7.1.1: + resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.51.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + /prettier@3.1.0: + resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} + engines: {node: '>=14'} + dev: true + + /pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /property-information@6.4.0: + resolution: {integrity: sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ==} + dev: true + + /public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + dependencies: + bn.js: 4.12.0 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + parse-asn1: 5.1.6 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + + /punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + /qs@6.11.2: + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + + /querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: true + + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: false + + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: true + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + dependencies: + glob: 7.2.3 + + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + dev: true + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /rollup@4.5.2: + resolution: {integrity: sha512-CRK1uoROBfkcqrZKyaFcqCcZWNsvJ6yVYZkqTlRocZhO2s5yER6Z3f/QaYtO8RGyloPnmhwgzuPQpNGeK210xQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.5.2 + '@rollup/rollup-android-arm64': 4.5.2 + '@rollup/rollup-darwin-arm64': 4.5.2 + '@rollup/rollup-darwin-x64': 4.5.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.5.2 + '@rollup/rollup-linux-arm64-gnu': 4.5.2 + '@rollup/rollup-linux-arm64-musl': 4.5.2 + '@rollup/rollup-linux-x64-gnu': 4.5.2 + '@rollup/rollup-linux-x64-musl': 4.5.2 + '@rollup/rollup-win32-arm64-msvc': 4.5.2 + '@rollup/rollup-win32-ia32-msvc': 4.5.2 + '@rollup/rollup-win32-x64-msvc': 4.5.2 + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /sandybox@1.1.2: + resolution: {integrity: sha512-JNXfp5HnlrEXnwXqhN2Hnn+zacK+UvP4Cgxtcy3ydKqr17s9Ysp2E3xL1uBApPfIX9vxSCLvfCFK5XEGVXatdw==} + dev: false + + /search-insights@2.11.0: + resolution: {integrity: sha512-Uin2J8Bpm3xaZi9Y8QibSys6uJOFZ+REMrf42v20AA3FUDUrshKkMEP6liJbMAHCm71wO6ls4mwAf7a3gFVxLw==} + dev: true + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /seroval@0.14.1: + resolution: {integrity: sha512-ZlC9y1KVDhZFdEHLYZup1RjKDutyX1tt3ffOauqRbRURa2vRr2NU/bHuVEuNEqR3zE2uCU3WM6LqH6Oinc3tWg==} + engines: {node: '>=10'} + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + dev: true + + /sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /shikiji-transformers@0.7.4: + resolution: {integrity: sha512-oykilNekcW2FnRGbvZm+RNWHYroSeCVMOaMMwAbxozZgpTdcJtHoA+1+MDFw6/o2hCkX88kKbxG6FwAZoUZ6WQ==} + dependencies: + shikiji: 0.7.4 + dev: true + + /shikiji@0.7.4: + resolution: {integrity: sha512-N5dmPvyhH/zfcsuWysUEAMwRJDMz26LUns2VEUs5y4Ozbf5jkAODU0Yswjcf/tZAwpFnk5x3y34dupFMnF2+NA==} + dependencies: + hast-util-to-html: 9.0.0 + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: true + + /siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true + + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false + + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: false + + /solid-js@1.8.6: + resolution: {integrity: sha512-yiH6ZfBBZ3xj/aU/PBpVKB+8r8WWp100NGF7k/Z0IrK9Y8Lv0jwvFiJY1cHdc6Tj7GqXArKnMBabM0m1k+LzkA==} + dependencies: + csstype: 3.1.2 + seroval: 0.14.1 + + /solid-refresh@0.5.3(solid-js@1.8.6): + resolution: {integrity: sha512-Otg5it5sjOdZbQZJnvo99TEBAr6J7PQ5AubZLNU6szZzg3RQQ5MX04oteBIIGDs0y2Qv8aXKm9e44V8z+UnFdw==} + peerDependencies: + solid-js: ^1.3 + dependencies: + '@babel/generator': 7.23.5 + '@babel/helper-module-imports': 7.22.15 + '@babel/types': 7.23.5 + solid-js: 1.8.6 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + dev: true + + /stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true + + /std-env@3.5.0: + resolution: {integrity: sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==} + dev: true + + /stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: true + + /stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + + /stringify-entities@4.0.3: + resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + /strip-literal@1.3.0: + resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} + dependencies: + acorn: 8.11.2 + dev: true + + /sucrase@3.34.0: + resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: true + + /tailwindcss@3.3.5: + resolution: {integrity: sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.5.3 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.0 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.31 + postcss-import: 15.1.0(postcss@8.4.31) + postcss-js: 4.0.1(postcss@8.4.31) + postcss-load-config: 4.0.2(postcss@8.4.31) + postcss-nested: 6.0.1(postcss@8.4.31) + postcss-selector-parser: 6.0.13 + resolve: 1.22.8 + sucrase: 3.34.0 + transitivePeerDependencies: + - ts-node + dev: true + + /tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /timers-browserify@2.0.12: + resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} + engines: {node: '>=0.6.0'} + dependencies: + setimmediate: 1.0.5 + dev: true + + /tinybench@2.5.1: + resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} + dev: true + + /tinypool@0.7.0: + resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy@2.2.0: + resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} + engines: {node: '>=14.0.0'} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + dev: true + + /ts-api-utils@1.0.3(typescript@5.3.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.3.2 + dev: false + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + + /tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + dev: true + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /turbo-darwin-64@1.10.16: + resolution: {integrity: sha512-+Jk91FNcp9e9NCLYlvDDlp2HwEDp14F9N42IoW3dmHI5ZkGSXzalbhVcrx3DOox3QfiNUHxzWg4d7CnVNCuuMg==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /turbo-darwin-arm64@1.10.16: + resolution: {integrity: sha512-jqGpFZipIivkRp/i+jnL8npX0VssE6IAVNKtu573LXtssZdV/S+fRGYA16tI46xJGxSAivrZ/IcgZrV6Jk80bw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-64@1.10.16: + resolution: {integrity: sha512-PpqEZHwLoizQ6sTUvmImcRmACyRk9EWLXGlqceogPZsJ1jTRK3sfcF9fC2W56zkSIzuLEP07k5kl+ZxJd8JMcg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-arm64@1.10.16: + resolution: {integrity: sha512-TMjFYz8to1QE0fKVXCIvG/4giyfnmqcQIwjdNfJvKjBxn22PpbjeuFuQ5kNXshUTRaTJihFbuuCcb5OYFNx4uw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-64@1.10.16: + resolution: {integrity: sha512-+jsf68krs0N66FfC4/zZvioUap/Tq3sPFumnMV+EBo8jFdqs4yehd6+MxIwYTjSQLIcpH8KoNMB0gQYhJRLZzw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-arm64@1.10.16: + resolution: {integrity: sha512-sKm3hcMM1bl0B3PLG4ifidicOGfoJmOEacM5JtgBkYM48ncMHjkHfFY7HrJHZHUnXM4l05RQTpLFoOl/uIo2HQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo@1.10.16: + resolution: {integrity: sha512-2CEaK4FIuSZiP83iFa9GqMTQhroW2QryckVqUydmg4tx78baftTOS0O+oDAhvo9r9Nit4xUEtC1RAHoqs6ZEtg==} + hasBin: true + optionalDependencies: + turbo-darwin-64: 1.10.16 + turbo-darwin-arm64: 1.10.16 + turbo-linux-64: 1.10.16 + turbo-linux-arm64: 1.10.16 + turbo-windows-64: 1.10.16 + turbo-windows-arm64: 1.10.16 + dev: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + /typescript@5.3.2: + resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} + engines: {node: '>=14.17'} + + /ufo@1.3.2: + resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + dependencies: + '@types/unist': 3.0.2 + dev: true + + /unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + dependencies: + '@types/unist': 3.0.2 + dev: true + + /unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + dependencies: + '@types/unist': 3.0.2 + dev: true + + /unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + dev: true + + /unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.22.1): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.1.1 + picocolors: 1.0.0 + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + + /url@0.11.3: + resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + dependencies: + punycode: 1.4.1 + qs: 6.11.2 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.12 + which-typed-array: 1.1.13 + dev: true + + /validate-html-nesting@1.2.2: + resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} + dev: true + + /vfile-location@5.0.2: + resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==} + dependencies: + '@types/unist': 3.0.2 + vfile: 6.0.1 + dev: true + + /vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + dev: true + + /vfile@6.0.1: + resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + dev: true + + /vite-node@0.34.6(@types/node@20.10.1): + resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} + engines: {node: '>=v14.18.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.4.2 + pathe: 1.1.1 + picocolors: 1.0.0 + vite: 5.0.2(@types/node@20.10.1) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite-plugin-monaco-editor@1.1.0(patch_hash=ml6vuvpbq2picjecjfyjy32u4e)(monaco-editor@0.44.0): + resolution: {integrity: sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==} + peerDependencies: + monaco-editor: '>=0.33.0' + dependencies: + monaco-editor: 0.44.0 + dev: true + patched: true + + /vite-plugin-node-polyfills@0.16.0(vite@4.5.0): + resolution: {integrity: sha512-uj1ymOmk7TliMxiivmXokpMY5gVMBpFPSZPLQSCv/LjkJGGKwyLjpbFL64dbYZEdFSUQ3tM7pbrxNh25yvhqOA==} + peerDependencies: + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 + dependencies: + '@rollup/plugin-inject': 5.0.5 + buffer-polyfill: /buffer@6.0.3 + node-stdlib-browser: 1.2.0 + process: 0.11.10 + vite: 4.5.0(@types/node@20.10.1) + transitivePeerDependencies: + - rollup + dev: true + + /vite-plugin-solid@2.7.2(solid-js@1.8.6)(vite@4.5.0): + resolution: {integrity: sha512-GV2SMLAibOoXe76i02AsjAg7sbm/0lngBlERvJKVN67HOrJsHcWgkt0R6sfGLDJuFkv2aBe14Zm4vJcNME+7zw==} + peerDependencies: + solid-js: ^1.7.2 + vite: ^3.0.0 || ^4.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/preset-typescript': 7.23.3(@babel/core@7.23.3) + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.8.6(@babel/core@7.23.3) + merge-anything: 5.1.7 + solid-js: 1.8.6 + solid-refresh: 0.5.3(solid-js@1.8.6) + vite: 4.5.0(@types/node@20.10.1) + vitefu: 0.2.5(vite@4.5.0) + transitivePeerDependencies: + - supports-color + dev: true + + /vite@4.5.0(@types/node@20.10.1): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.10.1 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vite@5.0.2(@types/node@20.10.1): + resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.10.1 + esbuild: 0.19.8 + postcss: 8.4.31 + rollup: 4.5.2 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vitefu@0.2.5(vite@4.5.0): + resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + vite: + optional: true + dependencies: + vite: 4.5.0(@types/node@20.10.1) + dev: true + + /vitepress@1.0.0-rc.31(@algolia/client-search@4.20.0)(search-insights@2.11.0)(typescript@5.3.2): + resolution: {integrity: sha512-ikH9pIjOOAbyoYAGBVfTz8TzuXp+UoWaIRMU4bw/oiTg8R65SbAaGKY84xx6TuL+f4VqUJ8lhzW82YyxSLvstA==} + hasBin: true + peerDependencies: + markdown-it-mathjax3: ^4.3.2 + postcss: ^8.4.31 + peerDependenciesMeta: + markdown-it-mathjax3: + optional: true + postcss: + optional: true + dependencies: + '@docsearch/css': 3.5.2 + '@docsearch/js': 3.5.2(@algolia/client-search@4.20.0)(search-insights@2.11.0) + '@types/markdown-it': 13.0.7 + '@vitejs/plugin-vue': 4.5.0(vite@5.0.2)(vue@3.3.9) + '@vue/devtools-api': 6.5.1 + '@vueuse/core': 10.6.1(vue@3.3.9) + '@vueuse/integrations': 10.6.1(focus-trap@7.5.4)(vue@3.3.9) + focus-trap: 7.5.4 + mark.js: 8.11.1 + minisearch: 6.3.0 + mrmime: 1.0.1 + shikiji: 0.7.4 + shikiji-transformers: 0.7.4 + vite: 5.0.2(@types/node@20.10.1) + vue: 3.3.9(typescript@5.3.2) + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/node' + - '@types/react' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - fuse.js + - idb-keyval + - jwt-decode + - less + - lightningcss + - nprogress + - qrcode + - react + - react-dom + - sass + - search-insights + - sortablejs + - stylus + - sugarss + - terser + - typescript + - universal-cookie + dev: true + + /vitest@0.34.6: + resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} + engines: {node: '>=v14.18.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + playwright: '*' + safaridriver: '*' + webdriverio: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + dependencies: + '@types/chai': 4.3.11 + '@types/chai-subset': 1.3.5 + '@types/node': 20.10.1 + '@vitest/expect': 0.34.6 + '@vitest/runner': 0.34.6 + '@vitest/snapshot': 0.34.6 + '@vitest/spy': 0.34.6 + '@vitest/utils': 0.34.6 + acorn: 8.11.2 + acorn-walk: 8.3.0 + cac: 6.7.14 + chai: 4.3.10 + debug: 4.3.4 + local-pkg: 0.4.3 + magic-string: 0.30.5 + pathe: 1.1.1 + picocolors: 1.0.0 + std-env: 3.5.0 + strip-literal: 1.3.0 + tinybench: 2.5.1 + tinypool: 0.7.0 + vite: 5.0.2(@types/node@20.10.1) + vite-node: 0.34.6(@types/node@20.10.1) + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + dev: true + + /vue-demi@0.14.6(vue@3.3.9): + resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.3.9(typescript@5.3.2) + dev: true + + /vue@3.3.9(typescript@5.3.2): + resolution: {integrity: sha512-sy5sLCTR8m6tvUk1/ijri3Yqzgpdsmxgj6n6yl7GXXCXqVbmW2RCXe9atE4cEI6Iv7L89v5f35fZRRr5dChP9w==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.3.9 + '@vue/compiler-sfc': 3.3.9 + '@vue/runtime-dom': 3.3.9 + '@vue/server-renderer': 3.3.9(vue@3.3.9) + '@vue/shared': 3.3.9 + typescript: 5.3.2 + dev: true + + /web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + dev: true + + /which-typed-array@1.1.13: + resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + dependencies: + isexe: 2.0.0 + + /why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false + + /yaml@2.3.4: + resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} + engines: {node: '>= 14'} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true + + /zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..3ff5faaa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - "apps/*" + - "packages/*" diff --git a/src/cli.ts b/src/cli.ts deleted file mode 100644 index 37cae36d..00000000 --- a/src/cli.ts +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env node - -import { program } from 'commander'; -import debug from 'debug'; -import { existsSync, readFileSync } from 'node:fs'; -import { readFile, rm } from 'node:fs/promises'; -import { join } from 'node:path'; -import * as url from 'node:url'; -import { webcrack } from './index.js'; - -const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); -const { version, description } = JSON.parse( - readFileSync(join(__dirname, '..', 'package.json'), 'utf8') -) as { version: string; description: string }; - -debug.enable('webcrack:*'); - -interface Options { - force: boolean; - output?: string; - mangle?: boolean; -} - -async function readStdin() { - let data = ''; - process.stdin.setEncoding('utf8'); - for await (const chunk of process.stdin) data += chunk; - return data; -} - -program - .version(version) - .description(description) - .option('-o, --output ', 'output directory for bundled files') - .option('-f, --force', 'overwrite output directory') - .option('-m, --mangle', 'mangle variable names') - .argument('[file]', 'input file, defaults to stdin') - .action(async (input: string | undefined) => { - const { output, force, mangle } = program.opts(); - const code = await (input ? readFile(input, 'utf8') : readStdin()); - - if (output) { - if (force || !existsSync(output)) { - await rm(output, { recursive: true, force: true }); - } else { - program.error('output directory already exists'); - } - } - - const result = await webcrack(code, { mangle }); - - if (output) { - await result.save(output); - } else { - console.log(result.code); - if (result.bundle) { - debug('webcrack:unpack')( - `${result.bundle.modules.size} modules are not displayed in the terminal. Use the --output option to save them` - ); - } - } - }) - .parse(); diff --git a/src/deobfuscator/index.ts b/src/deobfuscator/index.ts deleted file mode 100644 index 8f8aacc4..00000000 --- a/src/deobfuscator/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import debug from 'debug'; -import { - applyTransform, - applyTransformAsync, - applyTransforms, - AsyncTransform, -} from '../transforms'; -import mergeStrings from '../transforms/mergeStrings'; -import { findArrayRotator } from './arrayRotator'; -import controlFlowObject from './controlFlowObject'; -import controlFlowSwitch from './controlFlowSwitch'; -import deadCode from './deadCode'; -import { findDecoders } from './decoder'; -import inlineDecodedStrings from './inlineDecodedStrings'; -import inlineDecoderWrappers from './inlineDecoderWrappers'; -import inlineObjectProps from './inlineObjectProps'; -import { findStringArray } from './stringArray'; -import { Sandbox, VMDecoder } from './vm'; - -// https://astexplorer.net/#/gist/b1018df4a8daebfcb1daf9d61fe17557/4ff9ad0e9c40b9616956f17f59a2d9888cd62a4f - -export default { - name: 'deobfuscate', - tags: ['unsafe'], - async run(ast, state, sandbox) { - const logger = debug('webcrack:deobfuscate'); - if (!sandbox) return; - - const stringArray = findStringArray(ast); - logger( - stringArray - ? `String Array: ${stringArray.length} strings` - : 'String Array: no' - ); - if (!stringArray) return; - - const rotator = findArrayRotator(stringArray); - logger(`String Array Rotate: ${rotator ? 'yes' : 'no'}`); - - const decoders = findDecoders(stringArray); - logger(`String Array Encodings: ${decoders.length}`); - - state.changes += applyTransform(ast, inlineObjectProps).changes; - - for (const decoder of decoders) { - state.changes += applyTransform( - ast, - inlineDecoderWrappers, - decoder.path - ).changes; - } - - const vm = new VMDecoder(sandbox, stringArray, decoders, rotator); - state.changes += ( - await applyTransformAsync(ast, inlineDecodedStrings, { vm }) - ).changes; - - stringArray.path.remove(); - rotator?.remove(); - decoders.forEach(decoder => decoder.path.remove()); - state.changes += 2 + decoders.length; - - state.changes += applyTransforms( - ast, - [mergeStrings, deadCode, controlFlowObject, controlFlowSwitch], - 'mergeStrings, deadCode, controlFlow' - ).changes; - }, -} satisfies AsyncTransform; diff --git a/src/extractor/bundle.ts b/src/extractor/bundle.ts deleted file mode 100644 index eca0afee..00000000 --- a/src/extractor/bundle.ts +++ /dev/null @@ -1,99 +0,0 @@ -import traverse from '@babel/traverse'; -import * as m from '@codemod/matchers'; -import debug from 'debug'; -import { dirname, join, normalize } from 'node:path/posix'; -import { Module } from './module'; - -const logger = debug('webcrack:unpack'); - -export class Bundle { - type: 'webpack' | 'browserify'; - entryId: string; - modules: Map; - - constructor( - type: 'webpack' | 'browserify', - entryId: string, - modules: Map - ) { - this.type = type; - this.entryId = entryId; - this.modules = modules; - } - - applyMappings(mappings: Record>): void { - const mappingPaths = Object.keys(mappings); - if (mappingPaths.length === 0) return; - - const unusedMappings = new Set(mappingPaths); - - for (const module of this.modules.values()) { - traverse(module.ast, { - enter(path) { - for (const mappingPath of mappingPaths) { - if (mappings[mappingPath].match(path.node)) { - if (unusedMappings.has(mappingPath)) { - unusedMappings.delete(mappingPath); - } else { - logger(`Mapping ${mappingPath} is already used.`); - continue; - } - const resolvedPath = mappingPath.startsWith('./') - ? mappingPath - : `node_modules/${mappingPath}`; - module.path = resolvedPath; - path.stop(); - break; - } - } - }, - noScope: true, - }); - } - - if (unusedMappings.size > 0) { - logger(`Unused mappings: ${Array.from(unusedMappings).join(', ')}.`); - } - } - - /** - * Saves each module to a file and the bundle metadata to a JSON file. - * @param path Output directory - */ - async save(path: string): Promise { - const bundleJson = { - type: this.type, - entryId: this.entryId, - modules: Array.from(this.modules.values(), module => ({ - id: module.id, - path: module.path, - })), - }; - - if (process.env.browser) { - throw new Error('Not implemented.'); - } else { - const { mkdir, writeFile } = await import('node:fs/promises'); - await mkdir(path, { recursive: true }); - - await writeFile( - join(path, 'bundle.json'), - JSON.stringify(bundleJson, null, 2), - 'utf8' - ); - - await Promise.all( - Array.from(this.modules.values(), async module => { - const modulePath = normalize(join(path, module.path)); - if (!modulePath.startsWith(path)) { - throw new Error(`detected path traversal: ${module.path}`); - } - await mkdir(dirname(modulePath), { recursive: true }); - await writeFile(modulePath, module.code, 'utf8'); - }) - ); - } - } - - applyTransforms(): void {} -} diff --git a/src/extractor/index.ts b/src/extractor/index.ts deleted file mode 100644 index aa6a7fdd..00000000 --- a/src/extractor/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -import traverse, { Visitor, visitors } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import debug from 'debug'; -import { TransformState } from '../transforms'; -import { unpackBrowserify } from './browserify'; -import { Bundle } from './bundle'; -import { unpackWebpack } from './webpack'; - -export function unpackBundle( - ast: t.Node, - mappings: Record> = {} -): Bundle | undefined { - const options: { bundle: Bundle | undefined } = { bundle: undefined }; - const traverseOptions: Visitor[] = [ - unpackWebpack.visitor(options), - unpackBrowserify.visitor(options), - ]; - const visitor = visitors.merge(traverseOptions); - // @ts-expect-error regression from https://github.com/babel/babel/pull/15702 - visitor.noScope = traverseOptions.every(v => v.noScope); - traverse(ast, visitor, undefined, { changes: 0 }); - if (options.bundle) { - options.bundle.applyMappings(mappings); - options.bundle.applyTransforms(); - debug('webcrack:unpack')('Bundle:', options.bundle.type); - } - return options.bundle; -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index dd1d1b0f..00000000 --- a/src/index.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { parse } from '@babel/parser'; -import * as m from '@codemod/matchers'; -import debug from 'debug'; -import { join, normalize } from 'node:path'; -import deobfuscator from './deobfuscator'; -import debugProtection from './deobfuscator/debugProtection'; -import mergeObjectAssignments from './deobfuscator/mergeObjectAssignments'; -import selfDefending from './deobfuscator/selfDefending'; -import { - Sandbox, - createBrowserSandbox, - createNodeSandbox, -} from './deobfuscator/vm'; -import { unpackBundle } from './extractor'; -import { Bundle } from './extractor/bundle'; -import { - applyTransform, - applyTransformAsync, - applyTransforms, -} from './transforms'; -import blockStatement from './transforms/blockStatement'; -import jsx from './transforms/jsx'; -import jsxNew from './transforms/jsx-new'; -import mangle from './transforms/mangle'; -import sequence from './transforms/sequence'; -import splitVariableDeclarations from './transforms/splitVariableDeclarations'; -import unminify from './transforms/unminify'; -import { generate } from './utils/generator'; - -export interface WebcrackResult { - code: string; - bundle: Bundle | undefined; - /** - * Save the deobufscated code and the extracted bundle to the given directory. - * @param path Output directory - */ - save(path: string): Promise; -} - -export interface Options { - /** - * Decompile react components to JSX. - * @default true - */ - jsx?: boolean; - /** - * Extract modules from the bundle. - * @default true - */ - unpack?: boolean; - /** - * Deobfuscate the code. - * @default true - */ - deobfuscate?: boolean; - /** - * Mangle variable names. - * @default false - */ - mangle?: boolean; - /** - * Assigns paths to modules based on the given matchers. - * This will also rewrite `require()` calls to use the new paths. - * - * @example - * ```js - * m => ({ - * './utils/color.js': m.regExpLiteral('^#([0-9a-f]{3}){1,2}$') - * }) - * ``` - */ - mappings?: ( - m: typeof import('@codemod/matchers') - ) => Record>; - /** - * Function that executes a code expression and returns the result (typically from the obfuscator). - */ - sandbox?: Sandbox; -} - -function mergeOptions(options: Options): asserts options is Required { - const mergedOptions: Required = { - jsx: true, - unpack: true, - deobfuscate: true, - mangle: false, - mappings: () => ({}), - sandbox: process.env.browser ? createBrowserSandbox() : createNodeSandbox(), - ...options, - }; - Object.assign(options, mergedOptions); -} - -export async function webcrack( - code: string, - options: Options = {} -): Promise { - mergeOptions(options); - - if (process.env.browser) { - debug.enable('webcrack:*'); - } - - const isBookmarklet = /^javascript:./.test(code); - if (isBookmarklet) { - code = decodeURIComponent(code.replace(/^javascript:/, '')); - } - - const ast = parse(code, { - sourceType: 'unambiguous', - allowReturnOutsideFunction: true, - plugins: ['jsx'], - }); - - applyTransforms( - ast, - [blockStatement, sequence, splitVariableDeclarations], - 'prepare' - ); - - if (options.deobfuscate) - await applyTransformAsync(ast, deobfuscator, options.sandbox); - - // Normally unminify doesn't crawl the scope again, but when deobfuscation is disabled - // we have to do it for other transforms to work - const unminifyWrapper: typeof unminify = { - ...unminify, - visitor: () => ({ ...unminify.visitor(), noScope: options.deobfuscate }), - }; - applyTransform(ast, unminifyWrapper); - - if (options.mangle) applyTransform(ast, mangle); - - // TODO: Also merge unminify visitor (breaks selfDefending/debugProtection atm) - applyTransforms( - ast, - [ - // Have to run this after unminify to properly detect it - options.deobfuscate ? [selfDefending, debugProtection] : [], - options.jsx ? [jsx, jsxNew] : [], - ].flat() - ); - - if (options.deobfuscate) applyTransform(ast, mergeObjectAssignments); - - // Unpacking modifies the same AST and may result in imports not at top level - // so the code has to be generated before - const outputCode = generate(ast); - - const bundle = options.unpack - ? unpackBundle(ast, options.mappings(m)) - : undefined; - - return { - code: outputCode, - bundle, - async save(path) { - path = normalize(path); - if (process.env.browser) { - throw new Error('Not implemented.'); - } else { - const { mkdir, writeFile } = await import('node:fs/promises'); - await mkdir(path, { recursive: true }); - await writeFile(join(path, 'deobfuscated.js'), outputCode, 'utf8'); - await bundle?.save(path); - } - }, - }; -} diff --git a/src/transforms/mergeElseIf.ts b/src/transforms/mergeElseIf.ts deleted file mode 100644 index 132f4dcb..00000000 --- a/src/transforms/mergeElseIf.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { NodePath } from '@babel/traverse'; -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; - -export default { - name: 'mergeElseIf', - tags: ['safe'], - visitor() { - const nestedIf = m.capture(m.ifStatement()); - const matcher = m.ifStatement( - m.anything(), - m.anything(), - m.blockStatement([nestedIf]) - ); - - return { - IfStatement: { - exit(path) { - if (matcher.match(path.node)) { - const alternate = path.get('alternate') as NodePath; - alternate.replaceWith(nestedIf.current!); - this.changes++; - } - }, - }, - noScope: true, - }; - }, -} satisfies Transform; diff --git a/src/transforms/unminify.ts b/src/transforms/unminify.ts deleted file mode 100644 index dd0efe57..00000000 --- a/src/transforms/unminify.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Visitor, visitors } from '@babel/traverse'; -import { Transform, TransformState } from '.'; -import blockStatement from './blockStatement'; -import booleanIf from './booleanIf'; -import computedProperties from './computedProperties'; -import jsonParse from './jsonParse'; -import mergeElseIf from './mergeElseIf'; -import mergeStrings from './mergeStrings'; -import numberExpressions from './numberExpressions'; -import rawLiterals from './rawLiterals'; -import sequence from './sequence'; -import splitVariableDeclarations from './splitVariableDeclarations'; -import ternaryToIf from './ternaryToIf'; -import unminifyBooleans from './unminifyBooleans'; -import void0ToUndefined from './void0ToUndefined'; -import yoda from './yoda'; - -export default { - name: 'unminify', - tags: ['safe'], - visitor() { - const traverseOptions: Visitor[] = [ - rawLiterals.visitor(), - blockStatement.visitor(), - mergeStrings.visitor(), - computedProperties.visitor(), - splitVariableDeclarations.visitor(), - sequence.visitor(), - numberExpressions.visitor(), - unminifyBooleans.visitor(), - booleanIf.visitor(), - ternaryToIf.visitor(), - mergeElseIf.visitor(), - void0ToUndefined.visitor(), - yoda.visitor(), - jsonParse.visitor(), - ]; - const visitor = visitors.merge(traverseOptions); - // @ts-expect-error regression from https://github.com/babel/babel/pull/15702 - visitor.noScope = traverseOptions.every(t => t.noScope); - return visitor; - }, -} satisfies Transform; diff --git a/src/transforms/unminifyBooleans.ts b/src/transforms/unminifyBooleans.ts deleted file mode 100644 index 1bd43d38..00000000 --- a/src/transforms/unminifyBooleans.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; - -export default { - name: 'unminifyBooleans', - tags: ['safe'], - visitor: () => ({ - UnaryExpression(path) { - if (trueMatcher.match(path.node)) { - path.replaceWith(t.booleanLiteral(true)); - this.changes++; - } else if (falseMatcher.match(path.node)) { - path.replaceWith(t.booleanLiteral(false)); - this.changes++; - } - }, - noScope: true, - }), -} satisfies Transform; - -const trueMatcher = m.or( - m.unaryExpression('!', m.numericLiteral(0)), - m.unaryExpression('!', m.unaryExpression('!', m.numericLiteral(1))), - m.unaryExpression('!', m.unaryExpression('!', m.arrayExpression([]))) -); - -const falseMatcher = m.or( - m.unaryExpression('!', m.numericLiteral(1)), - m.unaryExpression('!', m.arrayExpression([])) -); diff --git a/src/transforms/void0ToUndefined.ts b/src/transforms/void0ToUndefined.ts deleted file mode 100644 index 645fbdcc..00000000 --- a/src/transforms/void0ToUndefined.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as t from '@babel/types'; -import * as m from '@codemod/matchers'; -import { Transform } from '.'; - -export default { - name: 'void0ToUndefined', - tags: ['safe'], - visitor: () => { - const matcher = m.unaryExpression('void', m.numericLiteral(0)); - return { - UnaryExpression: { - exit(path) { - if (matcher.match(path.node)) { - path.replaceWith(t.identifier('undefined')); - this.changes++; - } - }, - }, - noScope: true, - }; - }, -} satisfies Transform; diff --git a/src/utils/ast.ts b/src/utils/ast.ts deleted file mode 100644 index dfec7237..00000000 --- a/src/utils/ast.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as t from '@babel/types'; -import { generate } from './generator'; - -export function codePreview(node: t.Node): string { - const code = generate(node, { - minified: true, - shouldPrintComment: () => false, - }); - if (code.length > 100) { - return code.slice(0, 70) + ' … ' + code.slice(-30); - } - return code; -} - -export function getPropName(node: t.Node): string | undefined { - if (t.isIdentifier(node)) { - return node.name; - } - if (t.isStringLiteral(node)) { - return node.value; - } - if (t.isNumericLiteral(node)) { - return node.value.toString(); - } -} diff --git a/src/utils/generator.ts b/src/utils/generator.ts deleted file mode 100644 index 51628cf1..00000000 --- a/src/utils/generator.ts +++ /dev/null @@ -1,11 +0,0 @@ -import babelGenerate, { GeneratorOptions } from '@babel/generator'; -import * as t from '@babel/types'; - -const defaultOptions: GeneratorOptions = { jsescOption: { minimal: true } }; - -export function generate( - ast: t.Node, - options: GeneratorOptions = defaultOptions -): string { - return babelGenerate(ast, options).code; -} diff --git a/test/api.test.ts b/test/api.test.ts deleted file mode 100644 index 46a12ff2..00000000 --- a/test/api.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { readFile } from 'fs/promises'; -import { join } from 'path'; -import { describe, expect, test, vi } from 'vitest'; -import { webcrack } from '../src'; - -const obfuscatedSrc = await readFile( - join('test', 'samples', 'obfuscator.io.js'), - 'utf8' -); - -const webpackSrc = await readFile( - join('test', 'samples', 'webpack.js'), - 'utf8' -); - -describe('options', () => { - test('no deobfuscate', async () => { - await webcrack(webpackSrc, { deobfuscate: false }); - }); - - test('no unpack', async () => { - const result = await webcrack(webpackSrc, { unpack: false }); - expect(result.bundle).toBeUndefined(); - }); - - test('no jsx', async () => { - const result = await webcrack('React.createElement("div", null)', { - jsx: false, - }); - expect(result.code).toBe('React.createElement("div", null);'); - }); - - test('custom sandbox', async () => { - const sandbox = vi.fn((code: string) => - /* isolated-vm or something */ Promise.resolve(code) - ); - await webcrack(obfuscatedSrc, { sandbox }); - expect(sandbox).toHaveBeenCalledOnce(); - }); - - test('mangle', async () => { - const result = await webcrack('const foo = 1;', { mangle: true }); - expect(result.code).not.contain('foo'); - }); -}); diff --git a/test/deobfuscator.test.ts b/test/deobfuscator.test.ts deleted file mode 100644 index 8dea3d6d..00000000 --- a/test/deobfuscator.test.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { parse } from '@babel/parser'; -import traverse from '@babel/traverse'; -import assert from 'assert'; -import { readFile } from 'fs/promises'; -import { join } from 'node:path'; -import { describe, expect, test } from 'vitest'; -import { findStringArray } from '../src/deobfuscator/stringArray'; -import { webcrack } from '../src/index'; -import { generate } from '../src/utils/generator'; -import { - inlineFunctionAliases, - inlineVariableAliases, -} from '../src/utils/inline'; - -// Test samples -test.each([ - 'obfuscator.io.js', - 'obfuscator.io-rotator-unary.js', - 'obfuscator.io-multi-encoders.js', - 'obfuscator.io-function-wrapper.js', - 'obfuscator.io-calls-transform.js', - 'obfuscator.io-control-flow.js', - 'obfuscator.io-control-flow-split-strings.js', - 'obfuscator.io-control-flow-keys.js', - 'obfuscator.io-control-flow-partial-keys.js', - 'obfuscator.io-control-flow-switch-return.js', - 'obfuscator.io-control-flow-spread.js', - 'obfuscator.io-high.js', - 'simple-string-array.js', -])('deobfuscate %s', async filename => { - const result = await webcrack( - await readFile(join('test', 'samples', filename), 'utf8') - ); - expect(result.code).toMatchSnapshot(); -}); - -describe('find string array', async () => { - const ast = parse(await readFile('./test/samples/obfuscator.io.js', 'utf8')); - - test('function wrapper', () => { - const stringArray = findStringArray(ast); - expect(stringArray).toBeDefined(); - assert(stringArray); - expect(stringArray.name).toBe('__STRING_ARRAY__'); - expect(stringArray.references).toHaveLength(3); - expect(stringArray.length).toBe(25); - }); -}); - -describe('inline decoder', () => { - test('inline variable', () => { - const ast = parse(` - function decoder() {} - decoder(1); - (() => { - const alias = decoder, alias3 = alias; - alias(2); - alias3(3); - (() => { - let alias2; - (alias2 = alias)(4); - }); - let alias4; - alias4 = alias; - alias4(5); - }); - `); - traverse(ast, { - FunctionDeclaration(path) { - const binding = path.scope.getBinding('decoder')!; - inlineVariableAliases(binding); - path.stop(); - }, - }); - expect(generate(ast)).toMatchSnapshot(); - }); - - test('inline function', () => { - const ast = parse(` - function decoder() {} - decoder(1); - (() => { - function alias(a, b) { - return decoder(a - 625, b); - } - alias(2, 3); - (() => { - function alias2(a, b) { - return alias(b - -678, a); - } - alias2(4, 5); - })(); - })(); - `); - traverse(ast, { - FunctionDeclaration(path) { - const binding = path.scope.parent.bindings.decoder; - inlineFunctionAliases(binding); - path.stop(); - }, - }); - - expect(generate(ast)).toMatchSnapshot(); - }); -}); diff --git a/test/extractor.test.ts b/test/extractor.test.ts deleted file mode 100644 index 01d1b661..00000000 --- a/test/extractor.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -import assert from 'assert'; -import { readFile } from 'fs/promises'; -import { tmpdir } from 'os'; -import { join } from 'path'; -import { describe, expect, test } from 'vitest'; -import { webcrack } from '../src/index'; -import { relativePath, resolveDependencyTree } from '../src/utils/path'; - -// Test samples -test.each([ - 'webpack.js', - 'webpack-object.js', - 'webpack-esm.js', - 'webpack-var-injection.js', - 'webpack-jsonp-chunk.js', - 'webpack-0.11.x.js', - 'webpack5-object.js', - 'webpack5-esm.js', - 'browserify.js', - 'browserify-2.js', -])('extract %s', async filename => { - const { bundle } = await webcrack( - await readFile(join('test', 'samples', filename), 'utf8') - ); - expect(bundle).toMatchSnapshot(); -}); - -test('detect top-level bundle first', async () => { - const { bundle } = await webcrack( - await readFile( - join('test', 'samples', 'browserify-webpack-nested.js'), - 'utf8' - ) - ); - assert(bundle); - expect(bundle.type).toBe('browserify'); -}); - -describe('extractor', () => { - test('path mapping', async () => { - const { bundle } = await webcrack( - await readFile('./test/samples/webpack.js', 'utf8'), - { - mappings: m => ({ - './utils/color.js': m.stringLiteral('#FBC02D'), - package: m.numericLiteral(4), - }), - } - ); - expect(bundle).toBeDefined(); - assert(bundle); - expect(bundle).toMatchSnapshot(); - }); -}); - -test('prevent path traversal', async () => { - const code = await readFile('test/samples/webpack-path-traversal.js', 'utf8'); - const result = await webcrack(code); - const dir = join(tmpdir(), 'path-traversal-test'); - await expect(result.save(dir)).rejects.toThrow('path traversal'); -}); - -describe('paths', () => { - test('relative paths', () => { - expect(relativePath('./a.js', './x/y.js')).toBe('./x/y.js'); - expect(relativePath('./x/y.js', './a.js')).toBe('../a.js'); - expect(relativePath('./a.js', 'node_modules/lib')).toBe('lib'); - }); - - test('resolve browserify paths', () => { - const dependencies = { - 0: { 1: './a.js', 4: 'lib' }, - 1: { 2: '../bar/b.js' }, - 2: { 3: '../../c.js' }, - 3: {}, - 4: {}, - }; - expect(resolveDependencyTree(dependencies, '0')).toEqual({ - 0: 'tmp0/tmp1/index.js', - 1: 'tmp0/tmp1/a.js', - 2: 'tmp0/bar/b.js', - 3: 'c.js', - 4: 'node_modules/lib/index.js', - }); - }); - - test('resolve browserify paths 2', () => { - const dependencies = { - 1: {}, - 2: { 5: './v1', 6: './v4' }, - 3: {}, - 4: {}, - 5: { 3: './lib/bytesToUuid', 4: './lib/rng' }, - 6: { 3: './lib/bytesToUuid', 4: './lib/rng' }, - 7: { 1: 'number', 2: 'uuid' }, - }; - expect(resolveDependencyTree(dependencies, '7')).toEqual({ - 1: 'node_modules/number/index.js', - 2: 'node_modules/uuid/index.js', - 3: 'node_modules/uuid/lib/bytesToUuid.js', - 4: 'node_modules/uuid/lib/rng.js', - 5: 'node_modules/uuid/v1.js', - 6: 'node_modules/uuid/v4.js', - 7: 'index.js', - }); - }); - - // FIXME: utils/index.js instead of utils.js, can only know the real path by - // checking if all relative paths point to the correct modules? - test.skip('resolve browserify paths with index directory', () => { - const dependencies = { - 1: { 2: './utils', 4: './test' }, - 2: { 3: './lib', 4: '../test' }, - 3: {}, - 4: {}, - }; - expect(resolveDependencyTree(dependencies, '1')).toEqual({ - 1: 'index.js', - 2: 'utils/index.js', - 3: 'utils/lib.js', - 4: 'test.js', - }); - }); - - test('resolve circular browserify paths', () => { - const dependencies = { - 1: { 2: './utils' }, - 2: { 1: './base64' }, - 3: { 1: './base64' }, - }; - expect(resolveDependencyTree(dependencies, '3')).toEqual({ - 1: 'base64.js', - 2: 'utils.js', - 3: 'index.js', - }); - }); -}); diff --git a/test/rename.test.ts b/test/rename.test.ts deleted file mode 100644 index afa5225a..00000000 --- a/test/rename.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { parse } from '@babel/parser'; - -import traverse from '@babel/traverse'; -import { describe, expect, test } from 'vitest'; -import { renameFast, renameParameters } from '../src/utils/rename'; - -describe('rename variable', () => { - test('conflict with existing binding', () => { - const ast = parse('let a = 1; let b = a;'); - traverse(ast, { - Program(path) { - const binding = path.scope.getBinding('a')!; - renameFast(binding, 'b'); - - expect(path.scope.bindings).keys('b', '_b'); - }, - }); - expect(ast).toMatchInlineSnapshot(` - let b = 1; - let _b = b; - `); - }); - - test('different types of assignments', () => { - const ast = parse(` - var a = 1; - var a = 2; - a++; - [a] = [2]; - ({...a} = {}); - for (a of []); - for (a in []); - `); - traverse(ast, { - Program(path) { - const binding = path.scope.getBinding('a')!; - renameFast(binding, 'b'); - }, - }); - expect(ast).toMatchInlineSnapshot(` - var b = 1; - var b = 2; - b++; - [b] = [2]; - ({ - ...b - } = {}); - for (b of []); - for (b in []); - `); - }); -}); - -describe('rename parameters', () => { - test('fewer than specified', () => { - const ast = parse('function f(a, b, c) { a + b + c;}'); - traverse(ast, { - Function(path) { - renameParameters(path, ['x', 'y']); - }, - }); - expect(ast).toMatchInlineSnapshot(` - function f(x, y, c) { - x + y + c; - } - `); - }); - - test('more than specified', () => { - const ast = parse('function f(a, b, c) { a + b + c;}'); - traverse(ast, { - Function(path) { - renameParameters(path, ['x', 'y', 'z', 'w']); - }, - }); - expect(ast).toMatchInlineSnapshot(` - function f(x, y, z) { - x + y + z; - } - `); - }); -}); diff --git a/test/setup.ts b/test/setup.ts deleted file mode 100644 index 8a1e81a5..00000000 --- a/test/setup.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as t from '@babel/types'; -import { expect } from 'vitest'; -import { generate } from '../src/utils/generator'; - -expect.addSnapshotSerializer({ - test: (val: unknown) => t.isNode(val) && !('parentPath' in val), - serialize: (val: t.Node) => generate(val), -}); diff --git a/test/transforms.test.ts b/test/transforms.test.ts deleted file mode 100644 index 45a345a7..00000000 --- a/test/transforms.test.ts +++ /dev/null @@ -1,873 +0,0 @@ -import { parse } from '@babel/parser'; -import traverse from '@babel/traverse'; -import { Assertion, describe as describeVitest, expect, test } from 'vitest'; -import { webcrack } from '../src'; -import deadCode from '../src/deobfuscator/deadCode'; -import inlineObjectProps from '../src/deobfuscator/inlineObjectProps'; -import mergeObjectAssignments from '../src/deobfuscator/mergeObjectAssignments'; -import { Transform } from '../src/transforms'; -import blockStatement from '../src/transforms/blockStatement'; -import booleanIf from '../src/transforms/booleanIf'; -import computedProperties from '../src/transforms/computedProperties'; -import { applyTransform } from '../src/transforms/index'; -import jsonParse from '../src/transforms/jsonParse'; -import jsx from '../src/transforms/jsx'; -import jsxNew from '../src/transforms/jsx-new'; -import mergeElseIf from '../src/transforms/mergeElseIf'; -import mergeStrings from '../src/transforms/mergeStrings'; -import numberExpressions from '../src/transforms/numberExpressions'; -import rawLiterals from '../src/transforms/rawLiterals'; -import sequence from '../src/transforms/sequence'; -import splitVariableDeclarations from '../src/transforms/splitVariableDeclarations'; -import ternaryToIf from '../src/transforms/ternaryToIf'; -import unminify from '../src/transforms/unminify'; -import unminifyBooleans from '../src/transforms/unminifyBooleans'; -import void0ToUndefined from '../src/transforms/void0ToUndefined'; -import yoda from '../src/transforms/yoda'; - -function describe( - transform: Transform, - factory: ( - expect: (actualCode: string, options?: Options) => Assertion - ) => void -) { - return describeVitest(transform.name, () => { - factory((actualCode, options) => { - const ast = parse(actualCode, { - sourceType: 'unambiguous', - allowReturnOutsideFunction: true, - }); - traverse(ast); // to crawl scope and get bindings - applyTransform(ast, transform, options); - return expect(ast); - }); - }); -} - -test('decode bookmarklet', async () => { - const code = `javascript:(function()%7Balert('hello%20world')%3B%7D)()%3B`; - const result = await webcrack(code); - expect(result.code).toMatchInlineSnapshot(` - "(function () { - alert(\\"hello world\\"); - })();" - `); -}); - -describe(sequence, expectJS => { - test('to statements', () => - expectJS(` - if (a) b(), c(); - `).toMatchInlineSnapshot(` - if (a) { - b(); - c(); - } - `)); - - test('rearrange from return', () => - expectJS(` - function f() { - return a(), b(), c(); - } - `).toMatchInlineSnapshot(` - function f() { - a(); - b(); - return c(); - } - `)); - - test('return void', () => - expectJS(` - return void (a(), b()); - `).toMatchInlineSnapshot(` - a(); - b(); - return; - `)); - - test('rearrange from if', () => - expectJS(` - if (a(), b()) c(); - `).toMatchInlineSnapshot(` - a(); - if (b()) c(); - `)); - - test('rearrange from switch', () => - expectJS(` - switch (a(), b()) {} - `).toMatchInlineSnapshot(` - a(); - switch (b()) {} - `)); - - test('throw', () => - expectJS(` - throw a(), b(); - `).toMatchInlineSnapshot(` - a(); - throw b(); - `)); - - test('rearrange from for-in', () => - expectJS(` - for (let key in a = 1, object) {} - `).toMatchInlineSnapshot(` - a = 1; - for (let key in object) {} - `)); - - test('rearrange from for loop init', () => - expectJS(` - for((a(), b());;); - `).toMatchInlineSnapshot(` - a(); - b(); - for (;;); - `)); - - test('rearrange from for loop update', () => - expectJS(` - for(; i < 10; a(), b(), i++); - `).toMatchInlineSnapshot(` - for (; i < 10; i++) { - a(); - b(); - } - `)); - - test('rearrange variable declarator', () => - expectJS(` - var t = (o = null, o); - `).toMatchInlineSnapshot(` - o = null; - var t = o; - `)); - - test('dont rearrange variable declarator in for loop', () => - expectJS(` - for(let a = (b, c);;) {} - `).toMatchInlineSnapshot(` - b; - for (let a = c;;) {} - `)); -}); - -describe(splitVariableDeclarations, expectJS => { - test('split variable declaration', () => - expectJS(` - const a = 1, b = 2, c = 3; - `).toMatchInlineSnapshot(` - const a = 1; - const b = 2; - const c = 3; - `)); - - test('split exported variable declaration', () => - expectJS(` - export const a = 1, b = 2, c = 3; - `).toMatchInlineSnapshot(` - export const a = 1; - export const b = 2; - export const c = 3; - `)); - - test('dont split in for loop', () => - expectJS(` - for (let i = 0, j = 1; i < 10; i++, j++) var a, b; - `).toMatchInlineSnapshot(` - for (let i = 0, j = 1; i < 10; i++, j++) { - var a; - var b; - } - `)); -}); - -describe(computedProperties, expectJS => { - test('member expression', () => { - expectJS(` - require("foo")["default"]?.["_"]; - `).toMatchInlineSnapshot('require("foo").default?._;'); - }); - - test('object', () => { - expectJS(` - const x = { ["foo"](){}, ["bar"]: 1 }; - `).toMatchInlineSnapshot(` - const x = { - foo() {}, - bar: 1 - }; - `); - }); - - test('class', () => { - expectJS(` - class Foo { - ["foo"](){} - ["bar"] = 1; - } - `).toMatchInlineSnapshot(` - class Foo { - foo() {} - bar = 1; - } - `); - }); - - test('ignore invalid identifier', () => - expectJS(` - console["1"]("hello"); - `).toMatchInlineSnapshot('console["1"]("hello");')); -}); - -describe(rawLiterals, expectJS => { - test('string', () => - expectJS( - String.raw`f("\x61", '"', "\u270F\uFE0F", "\u2028\u2029\t")` - ).toMatchInlineSnapshot('f("a", "\\"", "✏️", "\\u2028\\u2029\\t");')); - - test('number', () => - expectJS('const a = 0x1;').toMatchInlineSnapshot('const a = 1;')); -}); - -describe(blockStatement, expectJS => { - test('if statement', () => - expectJS(` - if (a) b(); - `).toMatchInlineSnapshot(` - if (a) { - b(); - } - `)); - - test('while statement', () => - expectJS(` - while (a) b(); - `).toMatchInlineSnapshot(` - while (a) { - b(); - } - `)); - - test('for statement', () => - expectJS(` - for (;;) b(); - `).toMatchInlineSnapshot(` - for (;;) { - b(); - } - `)); - - test('for in statement', () => - expectJS(` - for (const key in object) b(); - `).toMatchInlineSnapshot(` - for (const key in object) { - b(); - } - `)); - - test('for of statement', () => - expectJS(` - for (const item of array) b(); - `).toMatchInlineSnapshot(` - for (const item of array) { - b(); - } - `)); - - test('arrow function', () => - expectJS(` - const x = () => (a(), b()); - `).toMatchInlineSnapshot(` - const x = () => { - return a(), b(); - }; - `)); - - test('ignore empty statement', () => - expectJS(` - while (arr.pop()); - `).toMatchInlineSnapshot(` - while (arr.pop()); - `)); -}); - -describe(numberExpressions, expectJS => { - test('simplify', () => - expectJS(` - console.log(-0x1021e + -0x7eac8 + 0x17 * 0xac9c); - `).toMatchInlineSnapshot('console.log(431390);')); - - test('simplify coerced strings', () => - expectJS(` - console.log(-"0xa6" - -331, -"0xa6"); - `).toMatchInlineSnapshot('console.log(165, -166);')); - - test('ignore string results', () => - expectJS(` - console.log(0x1021e + "test"); - `).toMatchInlineSnapshot('console.log(0x1021e + "test");')); - - test('keep divisions', () => - expectJS(` - console.log((-0x152f + 0x1281 * -0x1 + -0x18 * -0x1d1) / (0x83 * -0x1a + -0x19ea + 0x5f * 0x6a)); - `).toMatchInlineSnapshot('console.log(1000 / 30);')); -}); - -describe(unminifyBooleans, expectJS => { - test('true', () => { - expectJS('!0').toMatchInlineSnapshot('true;'); - expectJS('!!1').toMatchInlineSnapshot('true;'); - expectJS('!![]').toMatchInlineSnapshot('true;'); - }); - - test('false', () => { - expectJS('!1').toMatchInlineSnapshot('false;'); - expectJS('![]').toMatchInlineSnapshot('false;'); - }); -}); - -describe(booleanIf, expectJS => { - test('and', () => - expectJS(` - x && y && z(); - `).toMatchInlineSnapshot(` - if (x && y) { - z(); - } - `)); - - test('or', () => - expectJS(` - x || y || z(); - `).toMatchInlineSnapshot(` - if (!(x || y)) { - z(); - } - `)); -}); - -describe(deadCode, expectJS => { - test('always true', () => { - expectJS(` - if ("xyz" === "xyz") { - a(); - } else { - b(); - } - `).toMatchInlineSnapshot('a();'); - expectJS(` - if ("abc" === "xyz") { - a(); - } - `).toMatchInlineSnapshot(''); - expectJS(` - if ("xyz" !== "abc") { - a(); - } else { - b(); - } - `).toMatchInlineSnapshot('a();'); - expectJS(` - if ("xyz" !== "xyz") { - a(); - } - `).toMatchInlineSnapshot(''); - - expectJS(` - "xyz" === "xyz" ? a() : b(); - `).toMatchInlineSnapshot('a();'); - expectJS(` - "xyz" !== "abc" ? a() : b(); - `).toMatchInlineSnapshot('a();'); - }); - - test('always false', () => { - expectJS(` - if ("abc" === "xyz") { - a(); - } else { - b(); - } - `).toMatchInlineSnapshot('b();'); - expectJS(` - if ("abc" !== "abc") { - a(); - } else { - b(); - } - `).toMatchInlineSnapshot('b();'); - expectJS(` - if (!("abc" !== "xyz")) { - a(); - } else { - b(); - } - `).toMatchInlineSnapshot('b();'); - expectJS(` - if ("abc" === "xyz") a(); - `).toMatchInlineSnapshot(''); - - expectJS(` - "abc" === "xyz" ? a() : b(); - `).toMatchInlineSnapshot('b();'); - expectJS(` - "abc" !== "abc" ? a() : b(); - `).toMatchInlineSnapshot('b();'); - }); - - test('rename shadowed variables', () => { - expectJS(` - let x = 1; - if ("a" === "a") { - let x = 2; - let y = 3; - } - `).toMatchInlineSnapshot(` - let x = 1; - let _x = 2; - let y = 3; - `); - }); -}); - -describe(ternaryToIf, expectJS => { - test('statement', () => - expectJS(` - a ? b() : c(); - `).toMatchInlineSnapshot(` - if (a) { - b(); - } else { - c(); - } - `)); - - test('returned', () => - expectJS(` - return a ? b() : c(); - `).toMatchInlineSnapshot(` - if (a) { - return b(); - } else { - return c(); - } - `)); - - test('ignore expression', () => - expectJS(` - const x = a ? b() : c(); - `).toMatchInlineSnapshot('const x = a ? b() : c();')); -}); - -describe(mergeStrings, expectJS => { - test('only strings', () => - expectJS(` - "a" + "b" + "c"; - `).toMatchInlineSnapshot('"abc";')); - test('with variables', () => - expectJS(` - "a" + "b" + xyz + "c" + "d"; - `).toMatchInlineSnapshot('"ab" + xyz + "cd";')); -}); - -describe(mergeElseIf, expectJS => { - test('merge', () => - expectJS(` - if (x) { - } else { - if (y) {} - }`).toMatchInlineSnapshot('if (x) {} else if (y) {}')); - - test('ignore when it contains other statements', () => - expectJS(` - if (x) { - } else { - if (y) {} - z(); - }`).toMatchInlineSnapshot(` - if (x) {} else { - if (y) {} - z(); - } - `)); -}); - -describe(void0ToUndefined, expectJS => { - test('void 0', () => expectJS('void 0').toMatchInlineSnapshot('undefined;')); -}); - -describe(yoda, expectJS => { - test('strict equality', () => - expectJS('"red" === color').toMatchInlineSnapshot('color === "red";')); - test('loose equality', () => - expectJS('null == x').toMatchInlineSnapshot('x == null;')); - test('strict inequality', () => - expectJS('"red" !== color').toMatchInlineSnapshot('color !== "red";')); - test('loose inequality', () => - expectJS('null != x').toMatchInlineSnapshot('x != null;')); - test('less than', () => expectJS('0 < x').toMatchInlineSnapshot('x > 0;')); - test('less or equal', () => - expectJS('0 <= x').toMatchInlineSnapshot('x >= 0;')); - test('greater than', () => expectJS('0 > x').toMatchInlineSnapshot('x < 0;')); - test('greater or equal', () => - expectJS('0 >= x').toMatchInlineSnapshot('x <= 0;')); - test('multiply', () => expectJS('0 * x').toMatchInlineSnapshot('x * 0;')); - test('xor', () => expectJS('0 ^ x').toMatchInlineSnapshot('x ^ 0;')); - test('and', () => expectJS('0 & x').toMatchInlineSnapshot('x & 0;')); - test('or', () => expectJS('0 | x').toMatchInlineSnapshot('x | 0;')); - - test('string', () => - expectJS('"str" == x').toMatchInlineSnapshot('x == "str";')); - test('number', () => expectJS('1 == x').toMatchInlineSnapshot('x == 1;')); - test('negative number', () => - expectJS('-1 == x').toMatchInlineSnapshot('x == -1;')); - test('boolean', () => - expectJS('true == x').toMatchInlineSnapshot('x == true;')); - test('null', () => expectJS('null == x').toMatchInlineSnapshot('x == null;')); - test('undefined', () => - expectJS('undefined == x').toMatchInlineSnapshot('x == undefined;')); - test('NaN', () => expectJS('NaN == x').toMatchInlineSnapshot('x == NaN;')); - test('Infinity', () => - expectJS('Infinity == x').toMatchInlineSnapshot('x == Infinity;')); - - test('ignore other operators', () => - expectJS('2 + x').toMatchInlineSnapshot('2 + x;')); - - test('ignore when right side is a literal', () => - expectJS('1 === 2').toMatchInlineSnapshot('1 === 2;')); -}); - -describe(jsonParse, expectJS => { - test('array', () => - expectJS('JSON.parse("[1,2,3]")').toMatchInlineSnapshot('[1, 2, 3];')); - - test('large literal', () => - expectJS('JSON.parse("1000000000000000000000")').toMatchInlineSnapshot( - '1000000000000000000000;' - )); - - test('ignore invalid json', () => - expectJS('JSON.parse("abc")').toMatchInlineSnapshot('JSON.parse("abc");')); -}); - -describe(unminify, expectJS => { - test('logical expression to if and merge else-if', () => - expectJS(` - if (x) {} else {y && z();} - `).toMatchInlineSnapshot(` - if (x) {} else if (y) { - z(); - } - `)); - - test('returned ternary with sequence', () => - expectJS(` - return a ? (b(), c()) : d(); - `).toMatchInlineSnapshot(` - if (a) { - b(); - return c(); - } else { - return d(); - } - `)); - - test('merged string representation', () => - expectJS('x = "\uD83D" + "\uDC40";').toMatchInlineSnapshot('x = "👀";')); -}); - -describe(jsx, expectJS => { - test('tag name type', () => - expectJS('React.createElement("div", null);').toMatchInlineSnapshot( - '
    ;' - )); - - test('component type', () => - expectJS('React.createElement(TodoList, null);').toMatchInlineSnapshot( - ';' - )); - - test('deeply nested member expression type', () => - expectJS( - 'React.createElement(components.list.TodoList, null);' - ).toMatchInlineSnapshot( - ';' - )); - - test('rename component with conflicting name', () => - expectJS('function a(){} React.createElement(a, null);') - .toMatchInlineSnapshot(` - function _Component() {} - <_Component />; - `)); - - test('attributes', () => - expectJS( - 'React.createElement("div", { "data-hover": "tooltip", style: { display: "block" } });' - ).toMatchInlineSnapshot(` -
    ; - `)); - - test('spread attributes', () => - expectJS('React.createElement("div", {...props});').toMatchInlineSnapshot( - '
    ;' - )); - - test('children', () => - expectJS( - 'React.createElement("div", null, React.createElement("span", null, "Hello ", name));' - ).toMatchInlineSnapshot('
    Hello {name}
    ;')); - - test('fragment', () => - expectJS( - 'React.createElement(React.Fragment, null, React.createElement("span", null), "test");' - ).toMatchInlineSnapshot('<>test;')); - - test('fragment with key', () => - expectJS( - 'React.createElement(React.Fragment, { key: o })' - ).toMatchInlineSnapshot(';')); -}); - -describe(jsxNew, expectJS => { - test('tag name type', () => - expectJS('jsx("div", {});').toMatchInlineSnapshot('
    ;')); - - test('component type', () => - expectJS('jsx(TodoList, {});').toMatchInlineSnapshot( - ';' - )); - - test('deeply nested member expression type', () => - expectJS('jsx(components.list.TodoList, {});').toMatchInlineSnapshot( - ';' - )); - - test('rename component with conflicting name', () => - expectJS('function a(){} jsx(a, {});').toMatchInlineSnapshot(` - function _Component() {} - <_Component />; - `)); - - test('attributes', () => - expectJS( - 'jsx("div", { "data-hover": "tooltip", style: { display: "block" } });' - ).toMatchInlineSnapshot(` -
    ; - `)); - - test('spread attributes', () => - expectJS('jsx("div", {...props});').toMatchInlineSnapshot( - '
    ;' - )); - - test('children', () => - expectJS( - 'jsx("div", { children: jsxs("span", { children: ["Hello ", name ] }) });' - ).toMatchInlineSnapshot('
    Hello {name}
    ;')); - - test('component with key', () => - expectJS('jsx("div", {}, "test")').toMatchInlineSnapshot( - '
    ;' - )); - - test('array expression child', () => - expectJS('jsx("div", { children: [1] })').toMatchInlineSnapshot( - '
    {[1]}
    ;' - )); - - test('fragment', () => - expectJS( - 'jsxs(React.Fragment, { children: [jsx("span", {}), "test"] });' - ).toMatchInlineSnapshot('<>test;')); - - test('fragment with key', () => - expectJS('jsx(React.Fragment, {}, o)').toMatchInlineSnapshot( - ';' - )); -}); - -describe(inlineObjectProps, expectJS => { - test('inline property', () => - expectJS(` - const a = { x: 1 }; - console.log(a.x); - `).toMatchInlineSnapshot('console.log(1);')); - - test('ignore non-existent properties', () => - expectJS(` - const a = { x: 1 }; - console.log(a.__defineGetter__); - `).toMatchInlineSnapshot(` - const a = { - x: 1 - }; - console.log(a.__defineGetter__); - `)); - - test('ignore shared variable references', () => - expectJS(` - const a = { x: 1 }; - fn(a); - console.log(a.x); - `).toMatchInlineSnapshot(` - const a = { - x: 1 - }; - fn(a); - console.log(a.x); - `)); - - test('ignore variable assignment', () => - expectJS(` - let a = { x: 1 }; - a = { x: 2 }; - console.log(a.x); - `).toMatchInlineSnapshot(` - let a = { - x: 1 - }; - a = { - x: 2 - }; - console.log(a.x); - `)); - - test('ignore property assignment', () => - expectJS(` - const a = { x: 1 }; - a.x = 2; - console.log(a.x); - `).toMatchInlineSnapshot(` - const a = { - x: 1 - }; - a.x = 2; - console.log(a.x); - `)); - - test('ignore property assignment with array pattern', () => - expectJS(` - let a = { x: 1 }; - [a.x] = [2]; - console.log(a.x); - `).toMatchInlineSnapshot(` - let a = { - x: 1 - }; - [a.x] = [2]; - console.log(a.x); - `)); - - test('ignore property assignment with object pattern', () => - expectJS(` - let a = { x: 1 }; - ({ x: a.x } = { x: 2 }); - console.log(a.x); - `).toMatchInlineSnapshot(` - let a = { - x: 1 - }; - ({ - x: a.x - } = { - x: 2 - }); - console.log(a.x); - `)); - - test('ignore delete', () => - expectJS(` - const a = { x: 1 }; - delete a.x; - console.log(a.x); - `).toMatchInlineSnapshot(` - const a = { - x: 1 - }; - delete a.x; - console.log(a.x); - `)); - - test('ignore update expression', () => - expectJS(` - const a = { x: 1 }; - a.x++; - console.log(a.x); - `).toMatchInlineSnapshot(` - const a = { - x: 1 - }; - a.x++; - console.log(a.x); - `)); -}); - -describe(mergeObjectAssignments, expectJS => { - test('inline properties without inlining object', () => - expectJS(` - const obj = {}; - obj.foo = foo; - obj.bar = 1; - foo++; - return obj; - `).toMatchInlineSnapshot(` - const obj = { - foo: foo, - bar: 1 - }; - foo++; - return obj; - `)); - - test('inline properties and object', () => - expectJS(` - const obj = {}; - obj.foo = 'foo'; - return obj; - `).toMatchInlineSnapshot(` - return { - foo: 'foo' - }; - `)); - - test('computed properties', () => - expectJS(` - const obj = {}; - obj["a b c"] = 1; - obj[1] = 2; - return obj; - `).toMatchInlineSnapshot(` - return { - "a b c": 1, - 1: 2 - }; - `)); - - test('ignore circular reference', () => - expectJS(` - const obj = {}; - obj.foo = obj; - `).toMatchInlineSnapshot(` - const obj = {}; - obj.foo = obj; - `)); - - test('ignore call with possible circular reference', () => - expectJS(` - const obj = {}; - obj.foo = fn(); - `).toMatchInlineSnapshot(` - const obj = {}; - obj.foo = fn(); - `)); -}); diff --git a/tsconfig.build.json b/tsconfig.build.json deleted file mode 100644 index 0929a134..00000000 --- a/tsconfig.build.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", - "noEmit": false, - "declaration": true, - "emitDeclarationOnly": true, - }, - "include": [ - "./src" - ] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index dd21a420..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "noEmit": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "allowJs": true, - "checkJs": true, - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts", - "test/**/*.ts", - "*.js", - "*.ts", - ], -} diff --git a/turbo.json b/turbo.json new file mode 100644 index 00000000..3fb2c41a --- /dev/null +++ b/turbo.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "build": { + "dependsOn": [ + "^build" + ], + "outputs": [ + "dist/**" + ] + }, + "lint": {}, + "lint:fix": {}, + "dev": { + "cache": false, + "persistent": true + } + } +} diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index 4343ba83..00000000 --- a/vitest.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - test: { - forceRerunTriggers: ['test/samples/**'], - setupFiles: 'test/setup.ts', - include: ['test/**/*.test.ts'], - coverage: { - provider: 'istanbul', - }, - isolate: false, - useAtomics: true, - }, -}); diff --git a/vitest.workspace.json b/vitest.workspace.json new file mode 100644 index 00000000..822d9459 --- /dev/null +++ b/vitest.workspace.json @@ -0,0 +1,3 @@ +[ + "packages/*/vitest.config.ts" +] From 990f1a1f96c115b1ac30d2441d16c727a93e7b9f Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Fri, 1 Dec 2023 05:07:00 +0100 Subject: [PATCH 02/34] feat: unminify infinity --- packages/unminify/src/transforms/index.ts | 1 + packages/unminify/src/transforms/infinity.ts | 37 ++++++++++++++++++++ packages/unminify/test/infinity.test.ts | 16 +++++++++ 3 files changed, 54 insertions(+) create mode 100644 packages/unminify/src/transforms/infinity.ts create mode 100644 packages/unminify/test/infinity.test.ts diff --git a/packages/unminify/src/transforms/index.ts b/packages/unminify/src/transforms/index.ts index 2713ab43..0f071d49 100644 --- a/packages/unminify/src/transforms/index.ts +++ b/packages/unminify/src/transforms/index.ts @@ -1,5 +1,6 @@ export { default as blockStatements } from "./block-statements"; export { default as computedProperties } from "./computed-properties"; +export { default as infinity } from "./infinity"; export { default as jsonParse } from "./json-parse"; export { default as logicalToIf } from "./logical-to-if"; export { default as mergeElseIf } from "./merge-else-if"; diff --git a/packages/unminify/src/transforms/infinity.ts b/packages/unminify/src/transforms/infinity.ts new file mode 100644 index 00000000..b90a74d3 --- /dev/null +++ b/packages/unminify/src/transforms/infinity.ts @@ -0,0 +1,37 @@ +import * as t from "@babel/types"; +import * as m from "@codemod/matchers"; +import { Transform } from "@webcrack/ast-utils"; + +export default { + name: "infinity", + tags: ["safe"], + scope: true, + visitor: () => { + const infinityMatcher = m.binaryExpression( + "/", + m.numericLiteral(1), + m.numericLiteral(0), + ); + const negativeInfinityMatcher = m.binaryExpression( + "/", + m.unaryExpression("-", m.numericLiteral(1)), + m.numericLiteral(0), + ); + + return { + BinaryExpression: { + exit(path) { + if (path.scope.hasBinding("Infinity", { noGlobals: true })) return; + + if (infinityMatcher.match(path.node)) { + path.replaceWith(t.identifier("Infinity")); + this.changes++; + } else if (negativeInfinityMatcher.match(path.node)) { + path.replaceWith(t.unaryExpression("-", t.identifier("Infinity"))); + this.changes++; + } + }, + }, + }; + }, +} satisfies Transform; diff --git a/packages/unminify/test/infinity.test.ts b/packages/unminify/test/infinity.test.ts new file mode 100644 index 00000000..3d26a9fc --- /dev/null +++ b/packages/unminify/test/infinity.test.ts @@ -0,0 +1,16 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import { infinity } from "../src/transforms"; + +const expectJS = testTransform(infinity); + +test("infinity", () => expectJS("1/0").toMatchInlineSnapshot('Infinity;')); + +test("negative infinity", () => + expectJS("-1/0").toMatchInlineSnapshot('-Infinity;')); + +test("ignore when Infinity is declared in scope", () => + expectJS("let Infinity = 1; 1/0").toMatchInlineSnapshot(` + let Infinity = 1; + 1 / 0; + `)); From 2a4dbdc6f625a8ded0f7744290adc251518b0a26 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Fri, 1 Dec 2023 05:24:35 +0100 Subject: [PATCH 03/34] fix: turbo cache misses --- apps/playground/turbo.json | 4 +++- turbo.json | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/playground/turbo.json b/apps/playground/turbo.json index 445dc532..41d7e5f6 100644 --- a/apps/playground/turbo.json +++ b/apps/playground/turbo.json @@ -5,7 +5,9 @@ ], "pipeline": { "build": { - "dependsOn": [] + "dependsOn": [ + "topo" + ] } } } diff --git a/turbo.json b/turbo.json index 3fb2c41a..2018aa65 100644 --- a/turbo.json +++ b/turbo.json @@ -14,6 +14,11 @@ "dev": { "cache": false, "persistent": true + }, + "topo": { + "dependsOn": [ + "^topo" + ] } } } From 118df22a274c12820a0798dd644d3db5614ffe36 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Fri, 1 Dec 2023 06:21:24 +0100 Subject: [PATCH 04/34] feat: unflip negative infinity --- packages/unminify/src/transforms/yoda.ts | 5 ++++- packages/unminify/test/yoda.test.ts | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/unminify/src/transforms/yoda.ts b/packages/unminify/src/transforms/yoda.ts index a5eb94f3..9f8d7eef 100644 --- a/packages/unminify/src/transforms/yoda.ts +++ b/packages/unminify/src/transforms/yoda.ts @@ -28,7 +28,10 @@ export default { m.or( m.stringLiteral(), m.numericLiteral(), - m.unaryExpression("-", m.numericLiteral()), + m.unaryExpression( + "-", + m.or(m.numericLiteral(), m.identifier("Infinity")), + ), m.booleanLiteral(), m.nullLiteral(), m.identifier("undefined"), diff --git a/packages/unminify/test/yoda.test.ts b/packages/unminify/test/yoda.test.ts index ecdcb323..ee2c5dab 100644 --- a/packages/unminify/test/yoda.test.ts +++ b/packages/unminify/test/yoda.test.ts @@ -55,6 +55,9 @@ test("NaN", () => expectJS("NaN == x").toMatchInlineSnapshot("x == NaN;")); test("Infinity", () => expectJS("Infinity == x").toMatchInlineSnapshot("x == Infinity;")); +test("negative infinity", () => + expectJS("-Infinity == x").toMatchInlineSnapshot("x == -Infinity;")); + test("ignore other operators", () => expectJS("2 + x").toMatchInlineSnapshot("2 + x;")); From c969fb96bf8bcc0dfedc366d8c8bc48d0fa00b05 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:09:37 +0100 Subject: [PATCH 05/34] feat: transform jsx spread args --- packages/webcrack/src/transforms/jsx.ts | 16 ++- packages/webcrack/test/index.ts | 14 +++ packages/webcrack/test/jsx-new.test.ts | 61 ++++++++++ packages/webcrack/test/jsx.test.ts | 66 +++++++++++ packages/webcrack/test/transforms.test.ts | 135 +--------------------- 5 files changed, 153 insertions(+), 139 deletions(-) create mode 100644 packages/webcrack/test/index.ts create mode 100644 packages/webcrack/test/jsx-new.test.ts create mode 100644 packages/webcrack/test/jsx.test.ts diff --git a/packages/webcrack/src/transforms/jsx.ts b/packages/webcrack/src/transforms/jsx.ts index 8813ffa6..e6a80737 100644 --- a/packages/webcrack/src/transforms/jsx.ts +++ b/packages/webcrack/src/transforms/jsx.ts @@ -32,16 +32,20 @@ export default { // React.createElement(type, props, ...children) const elementMatcher = m.callExpression( constMemberExpression("React", "createElement"), - m.anyList(type, props, m.zeroOrMore(m.anyExpression())), + m.anyList( + type, + props, + m.zeroOrMore(m.or(m.anyExpression(), m.spreadElement())), + ), ); // React.createElement(React.Fragment, null, ...children) const fragmentMatcher = m.callExpression( constMemberExpression("React", "createElement"), - m.anyList( + m.anyList( constMemberExpression("React", "Fragment"), m.nullLiteral(), - m.zeroOrMore(m.anyExpression()), + m.zeroOrMore(m.or(m.anyExpression(), m.spreadElement())), ), ); @@ -148,13 +152,15 @@ function convertAttributes( } function convertChildren( - children: t.Expression[], -): (t.JSXText | t.JSXElement | t.JSXExpressionContainer)[] { + children: (t.Expression | t.SpreadElement)[], +): (t.JSXText | t.JSXElement | t.JSXSpreadChild | t.JSXExpressionContainer)[] { return children.map((child) => { if (t.isJSXElement(child)) { return child; } else if (t.isStringLiteral(child)) { return t.jsxText(child.value); + } else if (t.isSpreadElement(child)) { + return t.jsxSpreadChild(child.argument); } else { return t.jsxExpressionContainer(child); } diff --git a/packages/webcrack/test/index.ts b/packages/webcrack/test/index.ts new file mode 100644 index 00000000..38479fab --- /dev/null +++ b/packages/webcrack/test/index.ts @@ -0,0 +1,14 @@ +import { parse } from "@babel/parser"; +import { Transform, applyTransform } from "@webcrack/ast-utils"; +import { expect } from "vitest"; + +export function testTransform(transform: Transform) { + return (input: string, options?: Options) => { + const ast = parse(input, { + sourceType: "unambiguous", + allowReturnOutsideFunction: true, + }); + applyTransform(ast, transform, options); + return expect(ast); + }; +} diff --git a/packages/webcrack/test/jsx-new.test.ts b/packages/webcrack/test/jsx-new.test.ts new file mode 100644 index 00000000..edaf0ddf --- /dev/null +++ b/packages/webcrack/test/jsx-new.test.ts @@ -0,0 +1,61 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import jsxNew from "../src/transforms/jsx-new"; + +const expectJS = testTransform(jsxNew); + +test("tag name type", () => + expectJS('jsx("div", {});').toMatchInlineSnapshot("
    ;")); + +test("component type", () => + expectJS("jsx(TodoList, {});").toMatchInlineSnapshot(";")); + +test("deeply nested member expression type", () => + expectJS("jsx(components.list.TodoList, {});").toMatchInlineSnapshot( + ";", + )); + +test("rename component with conflicting name", () => + expectJS("function a(){} jsx(a, {});").toMatchInlineSnapshot(` + function _Component() {} + <_Component />; + `)); + +test("attributes", () => + expectJS( + 'jsx("div", { "data-hover": "tooltip", style: { display: "block" } });', + ).toMatchInlineSnapshot(` +
    ; + `)); + +test("spread attributes", () => + expectJS('jsx("div", {...props});').toMatchInlineSnapshot( + "
    ;", + )); + +test("children", () => + expectJS( + 'jsx("div", { children: jsxs("span", { children: ["Hello ", name ] }) });', + ).toMatchInlineSnapshot("
    Hello {name}
    ;")); + +test("component with key", () => + expectJS('jsx("div", {}, "test")').toMatchInlineSnapshot( + '
    ;', + )); + +test("array expression child", () => + expectJS('jsx("div", { children: [1] })').toMatchInlineSnapshot( + "
    {[1]}
    ;", + )); + +test("fragment", () => + expectJS( + 'jsxs(React.Fragment, { children: [jsx("span", {}), "test"] });', + ).toMatchInlineSnapshot("<>test;")); + +test("fragment with key", () => + expectJS("jsx(React.Fragment, {}, o)").toMatchInlineSnapshot( + ";", + )); diff --git a/packages/webcrack/test/jsx.test.ts b/packages/webcrack/test/jsx.test.ts new file mode 100644 index 00000000..505a0ffa --- /dev/null +++ b/packages/webcrack/test/jsx.test.ts @@ -0,0 +1,66 @@ +import { test } from "vitest"; +import { testTransform } from "."; +import jsx from "../src/transforms/jsx"; + +const expectJS = testTransform(jsx); + +test("tag name type", () => + expectJS('React.createElement("div", null);').toMatchInlineSnapshot( + "
    ;", + )); + +test("component type", () => + expectJS("React.createElement(TodoList, null);").toMatchInlineSnapshot( + ";", + )); + +test("deeply nested member expression type", () => + expectJS( + "React.createElement(components.list.TodoList, null);", + ).toMatchInlineSnapshot(";")); + +test("rename component with conflicting name", () => + expectJS("function a(){} React.createElement(a, null);") + .toMatchInlineSnapshot(` + function _Component() {} + <_Component />; + `)); + +test("attributes", () => + expectJS( + 'React.createElement("div", { "data-hover": "tooltip", style: { display: "block" } });', + ).toMatchInlineSnapshot(` +
    ; +`)); + +test("spread attributes", () => + expectJS('React.createElement("div", {...props});').toMatchInlineSnapshot( + "
    ;", + )); + +test("children", () => + expectJS( + 'React.createElement("div", null, React.createElement("span", null, "Hello ", name));', + ).toMatchInlineSnapshot("
    Hello {name}
    ;")); + +test("spread children", () => + expectJS( + 'React.createElement("div", null, ...children);', + ).toMatchInlineSnapshot("
    {...children}
    ;")); + +test("fragment", () => + expectJS( + 'React.createElement(React.Fragment, null, React.createElement("span", null), "test");', + ).toMatchInlineSnapshot("<>test;")); + +test("fragment with key", () => + expectJS( + "React.createElement(React.Fragment, { key: o })", + ).toMatchInlineSnapshot(";")); + +test("fragment with children", () => + expectJS( + 'React.createElement(React.Fragment, null, "test", ...children);', + ).toMatchInlineSnapshot("<>test{...children};")); diff --git a/packages/webcrack/test/transforms.test.ts b/packages/webcrack/test/transforms.test.ts index 056bc40a..e5a8d99a 100644 --- a/packages/webcrack/test/transforms.test.ts +++ b/packages/webcrack/test/transforms.test.ts @@ -1,27 +1,5 @@ -import { parse } from "@babel/parser"; -import { Transform, applyTransform } from "@webcrack/ast-utils"; -import { Assertion, describe as describeVitest, expect, test } from "vitest"; +import { expect, test } from "vitest"; import { webcrack } from "../src"; -import jsx from "../src/transforms/jsx"; -import jsxNew from "../src/transforms/jsx-new"; - -function describe( - transform: Transform, - factory: ( - expect: (actualCode: string, options?: Options) => Assertion, - ) => void, -) { - return describeVitest(transform.name, () => { - factory((actualCode, options) => { - const ast = parse(actualCode, { - sourceType: "unambiguous", - allowReturnOutsideFunction: true, - }); - applyTransform(ast, transform, options); - return expect(ast); - }); - }); -} test("decode bookmarklet", async () => { const code = `javascript:(function()%7Balert('hello%20world')%3B%7D)()%3B`; @@ -32,114 +10,3 @@ test("decode bookmarklet", async () => { })();" `); }); - -describe(jsx, (expectJS) => { - test("tag name type", () => - expectJS('React.createElement("div", null);').toMatchInlineSnapshot( - "
    ;", - )); - - test("component type", () => - expectJS("React.createElement(TodoList, null);").toMatchInlineSnapshot( - ";", - )); - - test("deeply nested member expression type", () => - expectJS( - "React.createElement(components.list.TodoList, null);", - ).toMatchInlineSnapshot(";")); - - test("rename component with conflicting name", () => - expectJS("function a(){} React.createElement(a, null);") - .toMatchInlineSnapshot(` - function _Component() {} - <_Component />; - `)); - - test("attributes", () => - expectJS( - 'React.createElement("div", { "data-hover": "tooltip", style: { display: "block" } });', - ).toMatchInlineSnapshot(` -
    ; - `)); - - test("spread attributes", () => - expectJS('React.createElement("div", {...props});').toMatchInlineSnapshot( - "
    ;", - )); - - test("children", () => - expectJS( - 'React.createElement("div", null, React.createElement("span", null, "Hello ", name));', - ).toMatchInlineSnapshot("
    Hello {name}
    ;")); - - test("fragment", () => - expectJS( - 'React.createElement(React.Fragment, null, React.createElement("span", null), "test");', - ).toMatchInlineSnapshot("<>test;")); - - test("fragment with key", () => - expectJS( - "React.createElement(React.Fragment, { key: o })", - ).toMatchInlineSnapshot(";")); -}); - -describe(jsxNew, (expectJS) => { - test("tag name type", () => - expectJS('jsx("div", {});').toMatchInlineSnapshot("
    ;")); - - test("component type", () => - expectJS("jsx(TodoList, {});").toMatchInlineSnapshot(";")); - - test("deeply nested member expression type", () => - expectJS("jsx(components.list.TodoList, {});").toMatchInlineSnapshot( - ";", - )); - - test("rename component with conflicting name", () => - expectJS("function a(){} jsx(a, {});").toMatchInlineSnapshot(` - function _Component() {} - <_Component />; - `)); - - test("attributes", () => - expectJS( - 'jsx("div", { "data-hover": "tooltip", style: { display: "block" } });', - ).toMatchInlineSnapshot(` -
    ; - `)); - - test("spread attributes", () => - expectJS('jsx("div", {...props});').toMatchInlineSnapshot( - "
    ;", - )); - - test("children", () => - expectJS( - 'jsx("div", { children: jsxs("span", { children: ["Hello ", name ] }) });', - ).toMatchInlineSnapshot("
    Hello {name}
    ;")); - - test("component with key", () => - expectJS('jsx("div", {}, "test")').toMatchInlineSnapshot( - '
    ;', - )); - - test("array expression child", () => - expectJS('jsx("div", { children: [1] })').toMatchInlineSnapshot( - "
    {[1]}
    ;", - )); - - test("fragment", () => - expectJS( - 'jsxs(React.Fragment, { children: [jsx("span", {}), "test"] });', - ).toMatchInlineSnapshot("<>test;")); - - test("fragment with key", () => - expectJS("jsx(React.Fragment, {}, o)").toMatchInlineSnapshot( - ";", - )); -}); From 95eb5fc8564fd5ce8bd901b2591d809c43eff6ba Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:11:33 +0100 Subject: [PATCH 06/34] fix: JSON/infinity tests --- packages/unminify/src/transforms/json-parse.ts | 5 ++++- packages/unminify/test/infinity.test.ts | 4 ++-- packages/unminify/test/json-parse.test.ts | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/unminify/src/transforms/json-parse.ts b/packages/unminify/src/transforms/json-parse.ts index 6b28127f..59d22ce0 100644 --- a/packages/unminify/src/transforms/json-parse.ts +++ b/packages/unminify/src/transforms/json-parse.ts @@ -15,7 +15,10 @@ export default { return { CallExpression: { exit(path) { - if (matcher.match(path.node) && !path.scope.hasBinding("JSON")) { + if ( + matcher.match(path.node) && + !path.scope.hasBinding("JSON", { noGlobals: true }) + ) { try { JSON.parse(string.current!); const parsed = parseExpression(string.current!); diff --git a/packages/unminify/test/infinity.test.ts b/packages/unminify/test/infinity.test.ts index 3d26a9fc..85a6cab2 100644 --- a/packages/unminify/test/infinity.test.ts +++ b/packages/unminify/test/infinity.test.ts @@ -4,10 +4,10 @@ import { infinity } from "../src/transforms"; const expectJS = testTransform(infinity); -test("infinity", () => expectJS("1/0").toMatchInlineSnapshot('Infinity;')); +test("infinity", () => expectJS("1/0").toMatchInlineSnapshot("Infinity;")); test("negative infinity", () => - expectJS("-1/0").toMatchInlineSnapshot('-Infinity;')); + expectJS("-1/0").toMatchInlineSnapshot("-Infinity;")); test("ignore when Infinity is declared in scope", () => expectJS("let Infinity = 1; 1/0").toMatchInlineSnapshot(` diff --git a/packages/unminify/test/json-parse.test.ts b/packages/unminify/test/json-parse.test.ts index 49a45695..f27c538c 100644 --- a/packages/unminify/test/json-parse.test.ts +++ b/packages/unminify/test/json-parse.test.ts @@ -5,11 +5,11 @@ import { jsonParse } from "../src/transforms"; const expectJS = testTransform(jsonParse); test("array", () => - expectJS('JSON.parse("[1,2,3]")').toMatchInlineSnapshot('JSON.parse("[1,2,3]");')); + expectJS('JSON.parse("[1,2,3]")').toMatchInlineSnapshot("[1, 2, 3];")); test("large literal", () => expectJS('JSON.parse("1000000000000000000000")').toMatchInlineSnapshot( - 'JSON.parse("1000000000000000000000");', + "1000000000000000000000;", )); test("ignore invalid json", () => From d9c21734e8f754ed211abdbff9ff837546a66c39 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:14:14 +0100 Subject: [PATCH 07/34] style: format with single quotes --- .prettierrc | 4 +- apps/docs/src/.vitepress/config.ts | 50 +++++------ apps/docs/src/.vitepress/theme/index.ts | 4 +- apps/docs/src/concepts/jsx.md | 4 +- apps/docs/src/concepts/unminify.md | 4 +- apps/docs/src/guide/api.md | 22 ++--- apps/docs/src/index.md | 2 +- apps/playground/src/App.tsx | 48 +++++----- .../playground/src/components/Breadcrumbs.tsx | 4 +- .../src/components/DirectoryNode.tsx | 6 +- apps/playground/src/components/FileNode.tsx | 2 +- apps/playground/src/components/FileTree.tsx | 12 +-- .../src/components/MonacoEditor.tsx | 30 +++---- apps/playground/src/components/Sidebar.tsx | 24 ++--- apps/playground/src/components/Tab.tsx | 4 +- .../src/context/DeobfuscateContext.tsx | 28 +++--- apps/playground/src/hooks/useTheme.ts | 16 ++-- apps/playground/src/index.tsx | 8 +- apps/playground/src/monaco/eval-selection.ts | 50 +++++------ .../src/monaco/placeholder-widget.ts | 20 ++--- apps/playground/src/sandbox.ts | 4 +- apps/playground/src/webcrack.worker.ts | 32 +++---- apps/playground/tailwind.config.ts | 32 +++---- apps/playground/vite.config.ts | 32 +++---- packages/ast-utils/src/ast.ts | 2 +- packages/ast-utils/src/generator.ts | 6 +- packages/ast-utils/src/index.ts | 12 +-- packages/ast-utils/src/inline.ts | 10 +-- packages/ast-utils/src/matcher.ts | 18 ++-- packages/ast-utils/src/matchers.d.ts | 6 +- packages/ast-utils/src/rename.ts | 10 +-- packages/ast-utils/src/transform.ts | 4 +- packages/ast-utils/test/rename.test.ts | 40 ++++----- packages/ast-utils/test/setup.ts | 8 +- packages/ast-utils/vitest.config.ts | 10 +-- packages/deobfuscate/src/array-rotator.ts | 20 ++--- .../deobfuscate/src/control-flow-object.ts | 20 ++--- .../deobfuscate/src/control-flow-switch.ts | 18 ++-- packages/deobfuscate/src/dead-code.ts | 24 ++--- packages/deobfuscate/src/debug-protection.ts | 18 ++-- packages/deobfuscate/src/decoder.ts | 14 +-- packages/deobfuscate/src/index.ts | 28 +++--- .../deobfuscate/src/inline-decoded-strings.ts | 14 +-- .../deobfuscate/src/inline-decoder-wappers.ts | 10 +-- .../deobfuscate/src/inline-object-props.ts | 12 +-- packages/deobfuscate/src/matchers.d.ts | 6 +- .../src/merge-object-assignments.ts | 18 ++-- packages/deobfuscate/src/self-defending.ts | 24 ++--- packages/deobfuscate/src/string-array.ts | 14 +-- packages/deobfuscate/src/vm.ts | 26 +++--- packages/deobfuscate/test/deobfuscate.test.ts | 52 +++++------ packages/deobfuscate/test/index.ts | 8 +- .../test/inline-object-props.test.ts | 26 +++--- .../test/merge-object-assignments.test.ts | 16 ++-- packages/deobfuscate/test/setup.ts | 8 +- packages/deobfuscate/vitest.config.ts | 10 +-- packages/unminify/src/index.ts | 14 +-- packages/unminify/src/matchers.d.ts | 6 +- .../src/transforms/block-statements.ts | 8 +- .../src/transforms/computed-properties.ts | 16 ++-- packages/unminify/src/transforms/index.ts | 30 +++---- packages/unminify/src/transforms/infinity.ts | 22 ++--- .../unminify/src/transforms/json-parse.ts | 14 +-- .../unminify/src/transforms/logical-to-if.ts | 16 ++-- .../unminify/src/transforms/merge-else-if.ts | 8 +- .../unminify/src/transforms/merge-strings.ts | 16 ++-- .../src/transforms/number-expressions.ts | 18 ++-- .../unminify/src/transforms/raw-literals.ts | 6 +- packages/unminify/src/transforms/sequence.ts | 16 ++-- .../transforms/split-variable-declarations.ts | 10 +-- .../unminify/src/transforms/ternary-to-if.ts | 10 +-- .../src/transforms/unminify-booleans.ts | 20 ++--- .../src/transforms/void-to-undefined.ts | 16 ++-- packages/unminify/src/transforms/yoda.ts | 44 ++++----- .../unminify/test/block-statements.test.ts | 20 ++--- .../unminify/test/computed-properties.test.ts | 14 +-- packages/unminify/test/index.ts | 8 +- packages/unminify/test/infinity.test.ts | 16 ++-- packages/unminify/test/json-parse.test.ts | 18 ++-- packages/unminify/test/logical-to-if.test.ts | 10 +-- packages/unminify/test/merge-else-if.test.ts | 12 +-- packages/unminify/test/merge-strings.test.ts | 10 +-- .../unminify/test/number-expressions.test.ts | 20 ++--- packages/unminify/test/raw-literals.test.ts | 12 +-- packages/unminify/test/sequence.test.ts | 28 +++--- packages/unminify/test/setup.ts | 8 +- .../test/split-variable-declarations.test.ts | 12 +-- packages/unminify/test/ternary-to-if.test.ts | 14 +-- .../unminify/test/unminify-booleans.test.ts | 20 ++--- .../unminify/test/void-to-undefined.test.ts | 12 +-- packages/unminify/test/yoda.test.ts | 74 +++++++-------- packages/unminify/vitest.config.ts | 10 +-- packages/unpack/src/browserify/bundle.ts | 6 +- packages/unpack/src/browserify/index.ts | 34 +++---- packages/unpack/src/browserify/module.ts | 4 +- packages/unpack/src/bundle.ts | 22 ++--- packages/unpack/src/index.ts | 22 ++--- packages/unpack/src/matchers.d.ts | 6 +- packages/unpack/src/module.ts | 6 +- packages/unpack/src/path.ts | 30 +++---- packages/unpack/src/webpack/bundle.ts | 30 +++---- packages/unpack/src/webpack/esm.ts | 36 ++++---- .../unpack/src/webpack/getDefaultExport.ts | 24 ++--- packages/unpack/src/webpack/index.ts | 58 ++++++------ packages/unpack/src/webpack/module.ts | 2 +- packages/unpack/src/webpack/varInjection.ts | 14 +-- packages/unpack/test/path.test.ts | 90 +++++++++---------- packages/unpack/test/setup.ts | 8 +- packages/unpack/test/unpack.test.ts | 52 +++++------ packages/unpack/vitest.config.ts | 10 +-- packages/webcrack/src/cli.ts | 40 ++++----- packages/webcrack/src/index.ts | 52 +++++------ packages/webcrack/src/matchers.d.ts | 6 +- .../babel-plugin-minify-mangle-names.d.ts | 6 +- packages/webcrack/src/transforms/jsx-new.ts | 28 +++--- packages/webcrack/src/transforms/jsx.ts | 20 ++--- packages/webcrack/src/transforms/mangle.ts | 14 +-- packages/webcrack/src/utils/platform.ts | 2 +- packages/webcrack/test/api.test.ts | 20 ++--- packages/webcrack/test/index.ts | 8 +- packages/webcrack/test/jsx-new.test.ts | 50 +++++------ packages/webcrack/test/jsx.test.ts | 54 +++++------ packages/webcrack/test/setup.ts | 8 +- packages/webcrack/test/transforms.test.ts | 6 +- packages/webcrack/vitest.config.ts | 10 +-- 125 files changed, 1171 insertions(+), 1169 deletions(-) diff --git a/.prettierrc b/.prettierrc index 0967ef42..544138be 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1 +1,3 @@ -{} +{ + "singleQuote": true +} diff --git a/apps/docs/src/.vitepress/config.ts b/apps/docs/src/.vitepress/config.ts index 30a918ee..e72730e8 100644 --- a/apps/docs/src/.vitepress/config.ts +++ b/apps/docs/src/.vitepress/config.ts @@ -1,60 +1,60 @@ -import { defineConfig } from "vitepress"; +import { defineConfig } from 'vitepress'; // https://vitepress.dev/reference/site-config export default defineConfig({ - title: "webcrack", - description: "Deobfuscate, unminify and unpack bundled javascript", - base: "/docs/", - outDir: "../dist/docs", + title: 'webcrack', + description: 'Deobfuscate, unminify and unpack bundled javascript', + base: '/docs/', + outDir: '../dist/docs', head: [ [ - "link", + 'link', { - rel: "icon", - href: "https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png", + rel: 'icon', + href: 'https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png', }, ], ], themeConfig: { // https://vitepress.dev/reference/default-theme-config - logo: "https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png", + logo: 'https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png', nav: [ - { text: "Home", link: "/" }, - { text: "Guide", link: "/guide/introduction" }, - { text: "Playground", link: "https://webcrack.netlify.app" }, + { text: 'Home', link: '/' }, + { text: 'Guide', link: '/guide/introduction' }, + { text: 'Playground', link: 'https://webcrack.netlify.app' }, ], sidebar: [ { - text: "Guide", + text: 'Guide', items: [ - { text: "Introduction", link: "/guide/introduction" }, - { text: "CLI", link: "/guide/cli" }, - { text: "Node.js API", link: "/guide/api" }, - { text: "Website", link: "/guide/web" }, + { text: 'Introduction', link: '/guide/introduction' }, + { text: 'CLI', link: '/guide/cli' }, + { text: 'Node.js API', link: '/guide/api' }, + { text: 'Website', link: '/guide/web' }, ], }, { - text: "Concepts", + text: 'Concepts', items: [ - { text: "Deobfuscation", link: "/concepts/deobfuscate" }, - { text: "Unminifying", link: "/concepts/unminify" }, - { text: "Bundle Unpacking", link: "/concepts/unpack" }, - { text: "JSX", link: "/concepts/jsx" }, + { text: 'Deobfuscation', link: '/concepts/deobfuscate' }, + { text: 'Unminifying', link: '/concepts/unminify' }, + { text: 'Bundle Unpacking', link: '/concepts/unpack' }, + { text: 'JSX', link: '/concepts/jsx' }, ], }, ], socialLinks: [ - { icon: "github", link: "https://github.com/j4k0xb/webcrack" }, + { icon: 'github', link: 'https://github.com/j4k0xb/webcrack' }, ], search: { - provider: "local", + provider: 'local', }, editLink: { - pattern: "https://github.com/j4k0xb/webcrack-ui/edit/master/docs/:path", + pattern: 'https://github.com/j4k0xb/webcrack-ui/edit/master/docs/:path', }, }, }); diff --git a/apps/docs/src/.vitepress/theme/index.ts b/apps/docs/src/.vitepress/theme/index.ts index 0c314338..be401193 100644 --- a/apps/docs/src/.vitepress/theme/index.ts +++ b/apps/docs/src/.vitepress/theme/index.ts @@ -1,5 +1,5 @@ -import DefaultTheme from "vitepress/theme"; -import "./custom.css"; +import DefaultTheme from 'vitepress/theme'; +import './custom.css'; export default { ...DefaultTheme, diff --git a/apps/docs/src/concepts/jsx.md b/apps/docs/src/concepts/jsx.md index 1484215a..b16c97db 100644 --- a/apps/docs/src/concepts/jsx.md +++ b/apps/docs/src/concepts/jsx.md @@ -6,9 +6,9 @@ This feature does the opposite. ```jsx React.createElement( - "div", + 'div', null, - React.createElement("span", null, "Hello ", name), + React.createElement('span', null, 'Hello ', name), ); ``` diff --git a/apps/docs/src/concepts/unminify.md b/apps/docs/src/concepts/unminify.md index 2064b361..bd78d582 100644 --- a/apps/docs/src/concepts/unminify.md +++ b/apps/docs/src/concepts/unminify.md @@ -5,7 +5,7 @@ Bundlers and obfuscators commonly minify code (remove new lines and whitespace, Most unminify sites just format the code, but webcrack also converts the syntax back to make it more readable and similar to the original code: ```js -console["\x6c\x6f\x67"]("\x61"); // console.log('a') +console['\x6c\x6f\x67']('\x61'); // console.log('a') x && y && z(); // if (x && y) z(); x || y || z(); // if (!(x || y)) z(); !0; // true @@ -15,6 +15,6 @@ x || y || z(); // if (!(x || y)) z(); return a(), b(), c(); // a(); b(); return c(); if ((a(), b())) c(); // a(); if (b()) c(); void 0; // undefined -"red" === color; // color === 'red' +'red' === color; // color === 'red' JSON.parse('{"a":1}'); // { a: 1 } ``` diff --git a/apps/docs/src/guide/api.md b/apps/docs/src/guide/api.md index 60f8297e..30ff7eba 100644 --- a/apps/docs/src/guide/api.md +++ b/apps/docs/src/guide/api.md @@ -12,21 +12,21 @@ npm install webcrack ## Basic Usage ```js -import { webcrack } from "webcrack"; +import { webcrack } from 'webcrack'; -const result = await webcrack("const a = 1+1;"); +const result = await webcrack('const a = 1+1;'); console.log(result.code); // 'const a = 2;' ``` Save the deobufscated code and the unpacked bundle to the given directory: ```js -import fs from "fs"; -import { webcrack } from "webcrack"; +import fs from 'fs'; +import { webcrack } from 'webcrack'; -const code = fs.readFileSync("bundle.js", "utf8"); +const code = fs.readFileSync('bundle.js', 'utf8'); const result = await webcrack(code); -await result.save("output-dir"); +await result.save('output-dir'); ``` ## Get Bundle Info @@ -68,14 +68,14 @@ If a matching node in the AST of a module is found, it will be renamed to the gi ```js const result = await webcrack(code, { mappings: (m) => ({ - "./utils/color.js": m.regExpLiteral("^#([0-9a-f]{3}){1,2}$"), - "lodash/index.js": m.memberExpression( - m.identifier("lodash"), - m.identifier("map"), + './utils/color.js': m.regExpLiteral('^#([0-9a-f]{3}){1,2}$'), + 'lodash/index.js': m.memberExpression( + m.identifier('lodash'), + m.identifier('map'), ), }), }); -await result.save("output-dir"); +await result.save('output-dir'); ``` New folder structure: diff --git a/apps/docs/src/index.md b/apps/docs/src/index.md index 06dd505d..95253c6c 100644 --- a/apps/docs/src/index.md +++ b/apps/docs/src/index.md @@ -4,7 +4,7 @@ layout: home title: Documentation hero: - name: "webcrack" + name: 'webcrack' logo: https://user-images.githubusercontent.com/55899582/231488871-e83fb827-1b25-4ec9-a326-b14244677e87.png actions: - theme: brand diff --git a/apps/playground/src/App.tsx b/apps/playground/src/App.tsx index 4405837e..e3c8d191 100644 --- a/apps/playground/src/App.tsx +++ b/apps/playground/src/App.tsx @@ -1,12 +1,12 @@ -import * as monaco from "monaco-editor"; -import { For, Show, createMemo, createSignal, onCleanup } from "solid-js"; -import { createStore } from "solid-js/store"; -import Breadcrumbs from "./components/Breadcrumbs"; -import MonacoEditor from "./components/MonacoEditor"; -import Sidebar from "./components/Sidebar"; -import Tab from "./components/Tab"; -import { DeobfuscateContextProvider } from "./context/DeobfuscateContext"; -import { DeobfuscateResult } from "./webcrack.worker"; +import * as monaco from 'monaco-editor'; +import { For, Show, createMemo, createSignal, onCleanup } from 'solid-js'; +import { createStore } from 'solid-js/store'; +import Breadcrumbs from './components/Breadcrumbs'; +import MonacoEditor from './components/MonacoEditor'; +import Sidebar from './components/Sidebar'; +import Tab from './components/Tab'; +import { DeobfuscateContextProvider } from './context/DeobfuscateContext'; +import { DeobfuscateResult } from './webcrack.worker'; export const [settings, setSettings] = createStore({ mangle: false, @@ -19,9 +19,9 @@ function App() { const [untitledCounter, setUntitledCounter] = createSignal(1); const [models, setModels] = createSignal([ monaco.editor.createModel( - "", - "javascript", - monaco.Uri.from({ scheme: "untitled", path: "Untitled-1" }), + '', + 'javascript', + monaco.Uri.from({ scheme: 'untitled', path: 'Untitled-1' }), ), ]); const [tabs, setTabs] = createSignal(models()); @@ -30,10 +30,10 @@ function App() { >(tabs()[0]); const fileModels = createMemo(() => - models().filter((m) => m.uri.scheme === "file"), + models().filter((m) => m.uri.scheme === 'file'), ); const untitledModels = createMemo(() => - models().filter((m) => m.uri.scheme === "untitled"), + models().filter((m) => m.uri.scheme === 'untitled'), ); const filePaths = createMemo(() => fileModels().map((model) => model.uri.fsPath), @@ -51,7 +51,7 @@ function App() { } function openFile(path: string) { - const model = fileModels().find((m) => m.uri.fsPath === "/" + path); + const model = fileModels().find((m) => m.uri.fsPath === '/' + path); if (!model) { return console.warn(`No model found for path: ${path}`); } @@ -64,7 +64,7 @@ function App() { setActiveTab(tabs()[index > 0 ? index - 1 : 1]); } setTabs(tabs().filter((t) => t !== tab)); - if (tab.uri.scheme === "untitled") { + if (tab.uri.scheme === 'untitled') { tab.dispose(); // FIXME: resets folder expansion state setModels(models().filter((m) => m !== tab)); @@ -74,10 +74,10 @@ function App() { function openUntitledTab() { setUntitledCounter(untitledCounter() + 1); const model = monaco.editor.createModel( - "", - "javascript", + '', + 'javascript', monaco.Uri.from({ - scheme: "untitled", + scheme: 'untitled', path: `Untitled-${untitledCounter()}`, }), ); @@ -95,7 +95,7 @@ function App() { return; } - if (!model || model.uri.scheme === "file") { + if (!model || model.uri.scheme === 'file') { model = openUntitledTab(); } @@ -110,14 +110,14 @@ function App() { ...result.files.map((file) => monaco.editor.createModel( file.code, - "javascript", + 'javascript', monaco.Uri.file(file.path), ), ), monaco.editor.createModel( result.code, - "javascript", - monaco.Uri.file("deobfuscated.js"), + 'javascript', + monaco.Uri.file('deobfuscated.js'), ), ]); } @@ -165,7 +165,7 @@ function App() {
    - + diff --git a/apps/playground/src/components/Breadcrumbs.tsx b/apps/playground/src/components/Breadcrumbs.tsx index 003b153e..5f42a2b0 100644 --- a/apps/playground/src/components/Breadcrumbs.tsx +++ b/apps/playground/src/components/Breadcrumbs.tsx @@ -1,11 +1,11 @@ -import { Index } from "solid-js"; +import { Index } from 'solid-js'; interface Props { path: string; } export default function Breadcrumbs(props: Props) { - const parts = () => props.path.replace(/^\.?\//, "").split("/"); + const parts = () => props.path.replace(/^\.?\//, '').split('/'); return (