From 475f29df68a3fbc7f847db2154ea873a28f261e1 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 16:51:34 -0400 Subject: [PATCH 01/11] refactor: wip new compose cli --- .github/workflows/cli.yml | 97 +- cli/.gitignore | 3 + cli/.gitmodules | 6 - cli/.npmignore | 5 +- cli/README.md | 237 +- cli/bases/accesscontrol.json | 56 + cli/bases/counter.json | 25 + cli/bases/diamond.json | 17 + cli/bases/erc1155.json | 70 + cli/bases/erc20.json | 45 + cli/bases/erc6909.json | 49 + cli/bases/erc721.json | 115 + cli/bases/libraries.json | 11 + cli/bases/owner.json | 67 + cli/bin/compose.js | 2 +- cli/eslint.config.js | 30 +- cli/index.js | 56 - cli/package.json | 43 +- cli/scripts/generate-templates-config.js | 142 - cli/src/adapters/foundryAdapter.ts | 115 + cli/src/adapters/hardhatAdapter.ts | 165 + cli/src/adapters/hashingAdapter.ts | 10 + .../adapters/interface/IFrameworkAdapter.ts | 40 + cli/src/adapters/interface/IHashingAdapter.ts | 12 + cli/src/comander.ts | 75 + cli/src/commands/init.js | 149 - cli/src/commands/listTemplates.js | 23 - cli/src/commands/update.js | 14 - cli/src/commands/version.js | 9 - cli/src/config/constants.js | 26 - cli/src/config/templates.json | 38 - cli/src/config/validateTemplatesConfig.js | 38 - cli/src/context/context.ts | 19 + cli/src/context/types.ts | 31 + cli/src/index.ts | 26 + cli/src/modules/config/catalog.ts | 47 + cli/src/modules/config/module.ts | 75 + cli/src/modules/config/selection.ts | 284 + cli/src/modules/config/types.ts | 55 + cli/src/modules/deployGeneration/model.ts | 97 + cli/src/modules/deployGeneration/module.ts | 65 + cli/src/modules/deployGeneration/renderers.ts | 127 + cli/src/modules/deployGeneration/types.ts | 17 + cli/src/modules/diamondGeneration/model.ts | 218 + cli/src/modules/diamondGeneration/module.ts | 58 + cli/src/modules/diamondGeneration/renderer.ts | 73 + cli/src/modules/diamondGeneration/types.ts | 22 + cli/src/modules/info/loader.ts | 104 + cli/src/modules/info/module.ts | 33 + cli/src/modules/info/output.ts | 146 + cli/src/modules/info/scanner.ts | 204 + cli/src/modules/info/types.ts | 35 + cli/src/modules/init/flags.ts | 33 + cli/src/modules/init/framework-deps.ts | 43 + cli/src/modules/init/module.ts | 297 + cli/src/modules/init/prompts.ts | 131 + cli/src/modules/init/types.ts | 80 + cli/src/modules/pipelineBuilder/module.ts | 59 + cli/src/modules/preflight/module.ts | 36 + cli/src/modules/projectDir/module.ts | 58 + cli/src/modules/scaffolding/facetSelection.ts | 93 + cli/src/modules/scaffolding/module.ts | 298 + cli/src/modules/scaffolding/paths.ts | 22 + cli/src/modules/scaffolding/storage.ts | 343 + cli/src/modules/scaffolding/types.ts | 52 + cli/src/modules/terminalOutput/module.ts | 203 + cli/src/modules/testGeneration/model.ts | 62 + cli/src/modules/testGeneration/module.ts | 58 + cli/src/modules/testGeneration/renderers.ts | 137 + cli/src/modules/testGeneration/types.ts | 14 + cli/src/modules/validation/module.ts | 217 + cli/src/modules/validation/state.ts | 69 + cli/src/modules/validation/types.ts | 91 + cli/src/modules/validation/validators.ts | 118 + cli/src/pipelines/entryPipeline.ts | 17 + cli/src/pipelines/infoPipeline.ts | 14 + cli/src/pipelines/initPipeline.ts | 131 + cli/src/prompts/initPrompts.js | 68 - cli/src/resolver/dependencyKey.ts | 11 + cli/src/resolver/dependencyRegistry.ts | 41 + cli/src/resolver/dependencyResolver.ts | 49 + cli/src/scaffold/frameworks/foundry.js | 46 - cli/src/scaffold/frameworks/hardhat.js | 50 - cli/src/scaffold/scaffold.js | 49 - cli/src/scaffold/utils/fileManager.js | 75 - cli/src/scaffold/utils/packageOrderer.js | 32 - cli/src/scaffold/utils/templateLoader.js | 51 - cli/src/scaffold/utils/tokenReplace.js | 40 - .../templates/counter/CounterDataFacet.sol | 32 + .../counter/CounterDecrementFacet.sol | 38 + .../counter/CounterIncrementFacet.sol | 35 + .../templates/counter/CounterResetFacet.sol | 33 + cli/src/templates/counter/CounterSetFacet.sol | 32 + cli/src/templates/default/foundry/.gitignore | 5 - cli/src/templates/default/foundry/README.md | 67 - .../templates/default/foundry/foundry.toml | 9 - .../templates/default/foundry/remappings.txt | 1 - .../default/foundry/script/Deploy.s.sol | 27 - .../templates/default/foundry/src/Diamond.sol | 18 - .../foundry/src/facets/CounterFacet.sol | 33 - .../default/foundry/test/CounterFacet.t.sol | 28 - .../default/hardhat/ts/minimal/.gitignore | 20 - .../default/hardhat/ts/minimal/README.md | 36 - .../hardhat/ts/minimal/contracts/Diamond.sol | 18 - .../minimal/contracts/facets/CounterFacet.sol | 33 - .../hardhat/ts/minimal/hardhat.config.ts | 8 - .../default/hardhat/ts/minimal/package.json | 10 - .../default/hardhat/ts/minimal/tsconfig.json | 13 - .../hardhat/ts/mocha-ethers/.gitignore | 20 - .../default/hardhat/ts/mocha-ethers/README.md | 92 - .../ts/mocha-ethers/contracts/Diamond.sol | 18 - .../contracts/facets/CounterFacet.sol | 33 - .../contracts/tests/CounterFacet.t.sol | 28 - .../hardhat/ts/mocha-ethers/hardhat.config.ts | 43 - .../mocha-ethers/ignition/modules/Counter.ts | 12 - .../hardhat/ts/mocha-ethers/package.json | 20 - .../ts/mocha-ethers/scripts/send-op-tx.ts | 23 - .../hardhat/ts/mocha-ethers/test/Counter.ts | 24 - .../hardhat/ts/mocha-ethers/tsconfig.json | 13 - .../hardhat/ts/node-runner-viem/.gitignore | 20 - .../hardhat/ts/node-runner-viem/README.md | 91 - .../ts/node-runner-viem/contracts/Diamond.sol | 18 - .../contracts/facets/CounterFacet.sol | 33 - .../contracts/tests/CounterFacet.t.sol | 34 - .../ts/node-runner-viem/hardhat.config.ts | 43 - .../ignition/modules/Counter.ts | 12 - .../hardhat/ts/node-runner-viem/package.json | 14 - .../ts/node-runner-viem/scripts/send-op-tx.ts | 32 - .../ts/node-runner-viem/test/Counter.ts | 25 - .../hardhat/ts/node-runner-viem/tsconfig.json | 13 - cli/src/templates/default/template.json | 14 - cli/src/templates/deploy/foundry-deploy.sol | 33 + .../templates/deploy/hardhat-ethers-deploy.ts | 26 + .../templates/deploy/hardhat-viem-deploy.ts | 25 + cli/src/templates/diamond/diamond.sol | 20 + .../ERC20IdentifierCollisionError.sol | 41 + .../examples/ERC20MissingExportSelector.sol | 32 + .../examples/ERC20SelectorCollisionError.sol | 37 + cli/src/templates/readme/foundry-readme.md | 50 + cli/src/templates/readme/hardhat-readme.md | 50 + cli/src/templates/test/foundry-test.sol | 32 + cli/src/templates/test/hardhat-ethers-test.ts | 28 + cli/src/templates/test/hardhat-viem-test.ts | 28 + cli/src/utils/arrays.ts | 28 + cli/src/utils/codegen.ts | 14 + cli/src/utils/errors.js | 25 - cli/src/utils/errors.ts | 28 + cli/src/utils/exec.js | 24 - cli/src/utils/exec.ts | 73 + cli/src/utils/files.ts | 178 + cli/src/utils/helpText.js | 29 - cli/src/utils/logger.js | 26 - .../{composeAsciiHeader.js => metadata.ts} | 11 +- cli/src/utils/objects.ts | 14 + cli/src/utils/prompts/initUtils.js | 29 - cli/src/utils/regex.ts | 10 + cli/src/utils/soliditySources.ts | 71 + cli/src/utils/solidityText.ts | 247 + cli/src/utils/strings.ts | 39 + cli/src/utils/terminal.ts | 79 + .../fixtures/template-variants.snapshot.json | 8 - cli/test/integration/cliEntry.test.js | 35 - cli/test/integration/scaffoldVariants.test.js | 147 - cli/test/unit/errors.test.js | 71 - cli/test/unit/fileManager.test.js | 71 - cli/test/unit/initOptions.test.js | 34 - cli/test/unit/initPrompts.test.js | 49 - cli/test/unit/packageOrderer.test.js | 30 - cli/test/unit/templateLoader.test.js | 59 - cli/test/unit/templateSnapshot.test.js | 18 - cli/test/unit/tokenReplace.test.js | 26 - cli/test/unit/validateTemplatesConfig.test.js | 19 - cli/test/unit/versionCommand.test.js | 18 - cli/tsconfig.json | 16 + package-lock.json | 12491 +++++++--------- package.json | 4 +- 176 files changed, 12144 insertions(+), 10164 deletions(-) delete mode 100644 cli/.gitmodules create mode 100644 cli/bases/accesscontrol.json create mode 100644 cli/bases/counter.json create mode 100644 cli/bases/diamond.json create mode 100644 cli/bases/erc1155.json create mode 100644 cli/bases/erc20.json create mode 100644 cli/bases/erc6909.json create mode 100644 cli/bases/erc721.json create mode 100644 cli/bases/libraries.json create mode 100644 cli/bases/owner.json delete mode 100755 cli/index.js delete mode 100644 cli/scripts/generate-templates-config.js create mode 100644 cli/src/adapters/foundryAdapter.ts create mode 100644 cli/src/adapters/hardhatAdapter.ts create mode 100644 cli/src/adapters/hashingAdapter.ts create mode 100644 cli/src/adapters/interface/IFrameworkAdapter.ts create mode 100644 cli/src/adapters/interface/IHashingAdapter.ts create mode 100644 cli/src/comander.ts delete mode 100644 cli/src/commands/init.js delete mode 100644 cli/src/commands/listTemplates.js delete mode 100644 cli/src/commands/update.js delete mode 100644 cli/src/commands/version.js delete mode 100644 cli/src/config/constants.js delete mode 100644 cli/src/config/templates.json delete mode 100644 cli/src/config/validateTemplatesConfig.js create mode 100644 cli/src/context/context.ts create mode 100644 cli/src/context/types.ts create mode 100644 cli/src/index.ts create mode 100644 cli/src/modules/config/catalog.ts create mode 100644 cli/src/modules/config/module.ts create mode 100644 cli/src/modules/config/selection.ts create mode 100644 cli/src/modules/config/types.ts create mode 100644 cli/src/modules/deployGeneration/model.ts create mode 100644 cli/src/modules/deployGeneration/module.ts create mode 100644 cli/src/modules/deployGeneration/renderers.ts create mode 100644 cli/src/modules/deployGeneration/types.ts create mode 100644 cli/src/modules/diamondGeneration/model.ts create mode 100644 cli/src/modules/diamondGeneration/module.ts create mode 100644 cli/src/modules/diamondGeneration/renderer.ts create mode 100644 cli/src/modules/diamondGeneration/types.ts create mode 100644 cli/src/modules/info/loader.ts create mode 100644 cli/src/modules/info/module.ts create mode 100644 cli/src/modules/info/output.ts create mode 100644 cli/src/modules/info/scanner.ts create mode 100644 cli/src/modules/info/types.ts create mode 100644 cli/src/modules/init/flags.ts create mode 100644 cli/src/modules/init/framework-deps.ts create mode 100644 cli/src/modules/init/module.ts create mode 100644 cli/src/modules/init/prompts.ts create mode 100644 cli/src/modules/init/types.ts create mode 100644 cli/src/modules/pipelineBuilder/module.ts create mode 100644 cli/src/modules/preflight/module.ts create mode 100644 cli/src/modules/projectDir/module.ts create mode 100644 cli/src/modules/scaffolding/facetSelection.ts create mode 100644 cli/src/modules/scaffolding/module.ts create mode 100644 cli/src/modules/scaffolding/paths.ts create mode 100644 cli/src/modules/scaffolding/storage.ts create mode 100644 cli/src/modules/scaffolding/types.ts create mode 100644 cli/src/modules/terminalOutput/module.ts create mode 100644 cli/src/modules/testGeneration/model.ts create mode 100644 cli/src/modules/testGeneration/module.ts create mode 100644 cli/src/modules/testGeneration/renderers.ts create mode 100644 cli/src/modules/testGeneration/types.ts create mode 100644 cli/src/modules/validation/module.ts create mode 100644 cli/src/modules/validation/state.ts create mode 100644 cli/src/modules/validation/types.ts create mode 100644 cli/src/modules/validation/validators.ts create mode 100644 cli/src/pipelines/entryPipeline.ts create mode 100644 cli/src/pipelines/infoPipeline.ts create mode 100644 cli/src/pipelines/initPipeline.ts delete mode 100644 cli/src/prompts/initPrompts.js create mode 100644 cli/src/resolver/dependencyKey.ts create mode 100644 cli/src/resolver/dependencyRegistry.ts create mode 100644 cli/src/resolver/dependencyResolver.ts delete mode 100644 cli/src/scaffold/frameworks/foundry.js delete mode 100644 cli/src/scaffold/frameworks/hardhat.js delete mode 100644 cli/src/scaffold/scaffold.js delete mode 100644 cli/src/scaffold/utils/fileManager.js delete mode 100644 cli/src/scaffold/utils/packageOrderer.js delete mode 100644 cli/src/scaffold/utils/templateLoader.js delete mode 100644 cli/src/scaffold/utils/tokenReplace.js create mode 100644 cli/src/templates/counter/CounterDataFacet.sol create mode 100644 cli/src/templates/counter/CounterDecrementFacet.sol create mode 100644 cli/src/templates/counter/CounterIncrementFacet.sol create mode 100644 cli/src/templates/counter/CounterResetFacet.sol create mode 100644 cli/src/templates/counter/CounterSetFacet.sol delete mode 100644 cli/src/templates/default/foundry/.gitignore delete mode 100644 cli/src/templates/default/foundry/README.md delete mode 100644 cli/src/templates/default/foundry/foundry.toml delete mode 100644 cli/src/templates/default/foundry/remappings.txt delete mode 100644 cli/src/templates/default/foundry/script/Deploy.s.sol delete mode 100644 cli/src/templates/default/foundry/src/Diamond.sol delete mode 100644 cli/src/templates/default/foundry/src/facets/CounterFacet.sol delete mode 100644 cli/src/templates/default/foundry/test/CounterFacet.t.sol delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/.gitignore delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/README.md delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/package.json delete mode 100644 cli/src/templates/default/hardhat/ts/minimal/tsconfig.json delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/README.md delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/package.json delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts delete mode 100644 cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/README.md delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/package.json delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts delete mode 100644 cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json delete mode 100644 cli/src/templates/default/template.json create mode 100644 cli/src/templates/deploy/foundry-deploy.sol create mode 100644 cli/src/templates/deploy/hardhat-ethers-deploy.ts create mode 100644 cli/src/templates/deploy/hardhat-viem-deploy.ts create mode 100644 cli/src/templates/diamond/diamond.sol create mode 100644 cli/src/templates/examples/ERC20IdentifierCollisionError.sol create mode 100644 cli/src/templates/examples/ERC20MissingExportSelector.sol create mode 100644 cli/src/templates/examples/ERC20SelectorCollisionError.sol create mode 100644 cli/src/templates/readme/foundry-readme.md create mode 100644 cli/src/templates/readme/hardhat-readme.md create mode 100644 cli/src/templates/test/foundry-test.sol create mode 100644 cli/src/templates/test/hardhat-ethers-test.ts create mode 100644 cli/src/templates/test/hardhat-viem-test.ts create mode 100644 cli/src/utils/arrays.ts create mode 100644 cli/src/utils/codegen.ts delete mode 100644 cli/src/utils/errors.js create mode 100644 cli/src/utils/errors.ts delete mode 100644 cli/src/utils/exec.js create mode 100644 cli/src/utils/exec.ts create mode 100644 cli/src/utils/files.ts delete mode 100644 cli/src/utils/helpText.js delete mode 100644 cli/src/utils/logger.js rename cli/src/utils/{composeAsciiHeader.js => metadata.ts} (77%) create mode 100644 cli/src/utils/objects.ts delete mode 100644 cli/src/utils/prompts/initUtils.js create mode 100644 cli/src/utils/regex.ts create mode 100644 cli/src/utils/soliditySources.ts create mode 100644 cli/src/utils/solidityText.ts create mode 100644 cli/src/utils/strings.ts create mode 100644 cli/src/utils/terminal.ts delete mode 100644 cli/test/fixtures/template-variants.snapshot.json delete mode 100644 cli/test/integration/cliEntry.test.js delete mode 100644 cli/test/integration/scaffoldVariants.test.js delete mode 100644 cli/test/unit/errors.test.js delete mode 100644 cli/test/unit/fileManager.test.js delete mode 100644 cli/test/unit/initOptions.test.js delete mode 100644 cli/test/unit/initPrompts.test.js delete mode 100644 cli/test/unit/packageOrderer.test.js delete mode 100644 cli/test/unit/templateLoader.test.js delete mode 100644 cli/test/unit/templateSnapshot.test.js delete mode 100644 cli/test/unit/tokenReplace.test.js delete mode 100644 cli/test/unit/validateTemplatesConfig.test.js delete mode 100644 cli/test/unit/versionCommand.test.js create mode 100644 cli/tsconfig.json diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index f1423ba9..c06a544a 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -15,7 +15,7 @@ on: workflow_dispatch: jobs: - lint-and-unit: + lint: runs-on: ubuntu-latest defaults: run: @@ -35,49 +35,19 @@ jobs: - name: Install dependencies run: npm ci - - name: Build templates registry - run: npm run build:templates + - name: Build TypeScript + run: npm run build - name: Lint run: npm run lint - - name: Run unit tests - run: npm run test:unit - - integration: - runs-on: ubuntu-latest - needs: lint-and-unit - defaults: - run: - working-directory: cli - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 24.x - cache: npm - cache-dependency-path: cli/package-lock.json - - - name: Install dependencies - run: npm ci - - - name: Build templates registry - run: npm run build:templates - - - name: Run integration tests - run: npm run test:integration - - template-smoke-tests: + smoke-tests: runs-on: ubuntu-latest strategy: fail-fast: false matrix: node-version: [20.x, 22.x, 24.x] - needs: lint-and-unit + needs: lint env: FOUNDRY_PROFILE: ci defaults: @@ -103,47 +73,41 @@ jobs: - name: Install dependencies run: npm ci - - name: Prepare libraries - run: npm run prepare:lib - - - name: Build templates registry - run: npm run build:templates + - name: Build TypeScript + run: npm run build - - name: Smoke test Foundry default template + - name: Smoke test Foundry counter base run: | set -euo pipefail rm -rf ci-foundry - node index.js init \ - --name ci-foundry \ - --template default \ + node dist/index.js init ci-foundry \ --framework foundry \ - --yes + --base counter \ + --ownership owner \ + --yes \ + --no-install-deps cd ci-foundry forge build - # TODO: Remove once @perfect-abstractions/compose is published to npm - # Currently, this make the Ci fail when trying to install the dependency. - # - name: Smoke test Hardhat default TypeScript template - # run: | - # set -euo pipefail - # rm -rf ci-hardhat - # node index.js init \ - # --name ci-hardhat \ - # --template default \ - # --framework hardhat \ - # --language typescript \ - # --no-install-deps \ - # --yes - # cd ci-hardhat - # npm install - # npm test + - name: Smoke test Hardhat counter base (ethers) + run: | + set -euo pipefail + rm -rf ci-hardhat + node dist/index.js init ci-hardhat \ + --framework hardhat \ + --toolbox ethers \ + --base counter \ + --ownership owner \ + --yes \ + --no-install-deps + cd ci-hardhat + npx hardhat compile pack-verify: runs-on: ubuntu-latest needs: - - lint-and-unit - - integration - - template-smoke-tests + - lint + - smoke-tests defaults: run: working-directory: cli @@ -162,9 +126,8 @@ jobs: - name: Install dependencies run: npm ci - - name: Build templates registry - run: npm run build:templates + - name: Build TypeScript + run: npm run build - name: Verify npm pack output run: npm run pack:check - diff --git a/cli/.gitignore b/cli/.gitignore index 3a2c4c75..00b5052a 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -2,6 +2,9 @@ node_modules/ coverage/ dist/ tmp/ +my-diamond/ +*.tsbuildinfo +.vscode/ .env .env.local diff --git a/cli/.gitmodules b/cli/.gitmodules deleted file mode 100644 index e5545047..00000000 --- a/cli/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "src/templates/default/foundry/lib/forge-std"] - path = src/templates/default/foundry/lib/forge-std - url = https://github.com/foundry-rs/forge-std.git -[submodule "src/templates/default/foundry/lib/Compose"] - path = src/templates/default/foundry/lib/Compose - url = https://github.com/Perfect-Abstractions/Compose.git diff --git a/cli/.npmignore b/cli/.npmignore index 8267d94b..01aa1a8f 100644 --- a/cli/.npmignore +++ b/cli/.npmignore @@ -3,5 +3,6 @@ test/ .github/ .cursor/ .tmp/ -lib/ -src/templates/**/foundry/lib/ +tsconfig.json +eslint.config.js +*.log diff --git a/cli/README.md b/cli/README.md index 131e1b30..ae40d6aa 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,162 +1,163 @@ # Compose CLI -Creates new diamond-based projects using the Compose Library. -Supports both [Foundry](https://book.getfoundry.sh/) and [Hardhat](https://hardhat.org/) frameworks. +Command-line toolkit for building, deploying, and managing diamond smart contracts using the Compose Library. Supports both [Foundry](https://book.getfoundry.sh/) and [Hardhat](https://hardhat.org/) frameworks. -## Create a new project with Compose CLI +## Quick Start ```bash npx @perfect-abstractions/compose-cli init ``` +This starts an interactive flow to scaffold a new diamond project with: +- Base preset selection (Counter, ERC-20, ERC-721, ERC-1155, ERC-6909) +- Extension facet selection +- Ownership and access control configuration +- Compose library facet selection +- Framework setup (Foundry or Hardhat) + ## Usage ```bash compose init [options] -compose templates +compose info +compose validate compose --version | -v compose --help | -h -compose update ``` -### Options +### `compose init` + +Scaffold a new Compose diamond project. -- `--name `: directory / package name for the new project. -- `--template `: template to use (see Template registry below). -- `--framework `: target framework. -- `--language `: source language (Hardhat only; defaults to `typescript` when omitted). -- `--install-deps` / `--no-install-deps`: whether to install npm dependencies for Hardhat templates (defaults to `true` unless disabled or using `--yes` with an explicit value). -- `--yes`: non-interactive mode. Skips prompts and fills missing values with sensible defaults. -- `--help`: print CLI help text. +**Options:** +- `--name `: directory name for the new project +- `--framework `: target framework +- `--toolbox `: Hardhat toolbox (default: ethers) +- `--base `: base preset (counter, erc-20, erc-721, erc-1155, erc-6909) +- `--ownership `: ownership model +- `--access-control `: access control facets to include +- `--libraries `: Compose library facets to include +- `--extensions `: extension facets to include +- `--examples`: include local example facets +- `--yes`: non-interactive mode with sensible defaults +- `--no-install-deps`: skip dependency installation When `--yes` is not provided, `compose init` will prompt for any values you omit. +### `compose info` + +Display a summary of the local project: +- All diamonds defined in the project +- Facets and their selectors +- Storage slot annotations +- Validation warnings + +### `compose validate` (Coming Soon...) + +Run static analysis on the local codebase: +- Storage layout validation +- Selector clash detection +- `exportSelectors` consistency checks +- Missing facet registration warnings + +Exit code non-zero on failure (CI-friendly). + +## Base Presets + +Each base preset provides a starting point for common diamond patterns: + +| Base | Description | Required Facets | +|------|-------------|-----------------| +| **Counter** (local) | Simple counter with increment/decrement | CounterDataFacet, CounterIncrementFacet, CounterDecrementFacet | +| **ERC-20** (package) | Fungible token standard | ERC20DataFacet, ERC20ApproveFacet, ERC20TransferFacet | +| **ERC-721** (package) | Non-fungible token standard | ERC721DataFacet, ERC721ApproveFacet, ERC721TransferFacet | +| **ERC-1155** (package) | Multi-token standard | ERC1155DataFacet, ERC1155ApproveFacet, ERC1155TransferFacet | +| **ERC-6909** (package) | Minimal multi-token standard | ERC6909DataFacet, ERC6909TransferFacet | + +Each base has compatible extension facets that are filtered during interactive selection to prevent cross-standard conflicts. + +## Examples + +### Interactive mode + +```bash +compose init +``` + +Follow the prompts to select framework, base, extensions, ownership, and access control. + ### Non-interactive examples ```bash -# Foundry default template -compose init --name my-foundry-app --template default --framework foundry --yes +# Foundry project with Counter base +compose init --name my-counter --framework foundry --base counter --ownership owner --yes -# Hardhat minimal TypeScript template, skip dependency install -compose init --name my-hardhat-minimal \ - --template default \ +# Hardhat project with ERC-20 base and extensions +compose init --name my-token \ --framework hardhat \ - --language typescript \ - --install-deps=false \ + --toolbox ethers \ + --base erc-20 \ + --ownership owner-two-step \ + --extensions ERC20BurnFacet,ERC20MintFacet \ + --libraries ERC165Facet \ --yes -# Hardhat mocha-ethers TypeScript template -compose init --name my-hardhat-mocha-ethers \ - --template default \ +# Hardhat project with Viem toolbox +compose init --name my-nft \ --framework hardhat \ - --language typescript \ + --toolbox viem \ + --base erc-721 \ + --ownership owner \ + --libraries DiamondUpgradeFacet,ERC165Facet \ --yes ``` +## Generated Project Structure -`compose templates` prints this information in a friendly format. +The CLI generates a project with the following structure: -## Development +``` +my-diamond/ + src/ + diamond/ + Diamond.sol + libraries/ + (Compose library facets) + facets/ + (Custom and extension facets) + test/ + Diamond.t.sol (Foundry) or Diamond.ts (Hardhat) + script/ + Deploy.s.sol (Foundry) or deploy.ts (Hardhat) + compose.json + foundry.toml or hardhat.config.ts +``` -From the `cli` directory: +## Documentation -```bash -npm install -npm run build:templates -npm run check -``` +Please see our [documentation website](https://compose.diamonds/docs/) for full documentation. -### Template registry generation -The template registry at `src/config/templates.json` is generated from per-template manifests under `src/templates/**/template.json`. +## Contributing -- To regenerate the registry after changing templates: +We welcome contributions from everyone! Compose grows through community involvement. -```bash -npm run build:templates -``` +Please see the [documentation for contributing](https://compose.diamonds/docs/contribution/how-to-contribute). -## Add a new template - -To make a new template: - -1. **Create the template folder** - - Add a new directory under `src/templates/`. - - Example: `src/templates/erc721`. - -2. **Add a `template.json` manifest** - - Place it at `src/templates//template.json`. - - Required fields: - - `id`: the template id (must match ``). - - `name`: human‑readable name shown in `compose templates`. - - `description`: short description. - - `variants`: list of variant ids (see below). - - `compatibility.frameworks`: array of supported frameworks, e.g. `["foundry"]` or `["foundry","hardhat"]`. - - Example: - ```json - { - "id": "erc721", - "name": "ERC‑721 Diamond", - "description": "Diamond project with an ERC‑721 facet", - "variants": [ - "erc721-foundry", - "erc721-hardhat-minimal" - ], - "compatibility": { - "frameworks": ["foundry", "hardhat"] - } - } - ``` - -3. **Add variant directories** - - Variant ids follow the pattern: `-[-]`. - - The generator maps variants to paths as follows: - - **Foundry**: `templates//foundry` - - Example variant id: `erc721-foundry` → `src/templates/erc721/foundry` - - **Hardhat (no project type)**: `templates//hardhat` - - Example variant id: `erc721-hardhat` → `src/templates/erc721/hardhat` - - **Hardhat with project type (TypeScript/JS layout)**: - - Path pattern: `templates//hardhat/ts/` - - Example variant id: `erc721-hardhat-minimal` → `src/templates/erc721/hardhat/ts/minimal` - - Place the scaffolded project files (contracts, configs, tests, etc.) inside each variant directory. - -4. **Language detection** - - The CLI infers the language from the variant path: - - Paths containing `/ts/` → `language: "typescript"`. - - Paths containing `/js/` → `language: "javascript"`. - - For Foundry templates, language is not set on the variant; the framework alone is enough. - -5. **Regenerate the templates registry** - - From the `cli` directory run: - ```bash - npm run build:templates - ``` - - This rebuilds `src/config/templates.json` from all `template.json` manifests and validates the result. - -6. **Verify your template is available** - - Run: - ```bash - node index.js templates - ``` - - Confirm your new template and variants appear in the list. - -7. **Smoke‑test the template** - - Use your new template to scaffold a project: - ```bash - node index.js init --name my-test-project --template --framework --yes - ``` - - Then run the framework’s own test / build commands in the generated project. - -### Test the CLI locally +--- -```bash -npm link -``` +
-This will create a symlink to the CLI in your global `node_modules` directory. +**Compose is evolving with your help. Join us in building the future of smart contract development.** -You can then test the CLI by running: +**-Nick & The Compose Community** -```bash -compose --help -``` + + +### Made with 🩵 by the [Compose Community](https://github.com/Perfect-Abstractions/Compose/graphs/contributors) + + + + + + diff --git a/cli/bases/accesscontrol.json b/cli/bases/accesscontrol.json new file mode 100644 index 00000000..5347ef3c --- /dev/null +++ b/cli/bases/accesscontrol.json @@ -0,0 +1,56 @@ +{ + "access-control": { + "label": "AccessControl", + "order": 9, + "access": true, + "accessType": "roles", + "required": { + "AccessControlDataFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Data/AccessControlDataFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Data/AccessControlDataMod.sol" + }, + "AccessControlGrantFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Grant/AccessControlGrantFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Grant/AccessControlGrantMod.sol" + }, + "AccessControlRevokeFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Revoke/AccessControlRevokeFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Revoke/AccessControlRevokeMod.sol" + } + }, + "optional": { + "AccessControlAdminFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Admin/AccessControlAdminFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Admin/AccessControlAdminMod.sol" + }, + "AccessControlGrantBatchFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Batch/Grant/AccessControlGrantBatchFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Batch/Grant/AccessControlGrantBatchMod.sol" + }, + "AccessControlRevokeBatchFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Batch/Revoke/AccessControlRevokeBatchFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Batch/Revoke/AccessControlRevokeBatchMod.sol" + }, + "AccessControlPausableFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Pausable/AccessControlPausableFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Pausable/AccessControlPausableMod.sol" + }, + "AccessControlRenounceFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Renounce/AccessControlRenounceFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Renounce/AccessControlRenounceMod.sol" + }, + "AccessControlTemporalDataFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Temporal/Data/AccessControlTemporalDataFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Temporal/Data/AccessControlTemporalDataMod.sol" + }, + "AccessControlTemporalGrantFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Temporal/Grant/AccessControlTemporalGrantFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Temporal/Grant/AccessControlTemporalGrantMod.sol" + }, + "AccessControlTemporalRevokeFacet": { + "path": "@perfect-abstractions/compose/access/AccessControl/Temporal/Revoke/AccessControlTemporalRevokeFacet.sol", + "mod": "@perfect-abstractions/compose/access/AccessControl/Temporal/Revoke/AccessControlTemporalRevokeMod.sol" + } + } + } +} diff --git a/cli/bases/counter.json b/cli/bases/counter.json new file mode 100644 index 00000000..d1857f3b --- /dev/null +++ b/cli/bases/counter.json @@ -0,0 +1,25 @@ +{ + "counter": { + "label": "Counter", + "order": 2, + "required": { + "CounterDataFacet": { + "path": "./src/templates/counter/CounterDataFacet.sol" + }, + "CounterIncrementFacet": { + "path": "./src/templates/counter/CounterIncrementFacet.sol" + } + }, + "optional": { + "CounterDecrementFacet": { + "path": "./src/templates/counter/CounterDecrementFacet.sol" + }, + "CounterResetFacet": { + "path": "./src/templates/counter/CounterResetFacet.sol" + }, + "CounterSetFacet": { + "path": "./src/templates/counter/CounterSetFacet.sol" + } + } + } +} diff --git a/cli/bases/diamond.json b/cli/bases/diamond.json new file mode 100644 index 00000000..e24dd1c6 --- /dev/null +++ b/cli/bases/diamond.json @@ -0,0 +1,17 @@ +{ + "diamond": { + "label": "Diamond", + "pragma": ">=0.8.30", + "compilerVersion": "0.8.30", + "required": { + "DiamondInspectFacet": { + "path": "@perfect-abstractions/compose/diamond/DiamondInspectFacet.sol" + } + }, + "optional": { + "DiamondUpgradeFacet": { + "path": "@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol" + } + } + } +} diff --git a/cli/bases/erc1155.json b/cli/bases/erc1155.json new file mode 100644 index 00000000..9e94c89c --- /dev/null +++ b/cli/bases/erc1155.json @@ -0,0 +1,70 @@ +{ + "erc-1155": { + "label": "ERC-1155", + "order": 5, + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC1155.sol", + "id": "type(IERC1155).interfaceId", + "comments": [ + "Register ERC-1155 interface support." + ] + }, + "required": { + "ERC1155DataFacet": { + "path": "@perfect-abstractions/compose/token/ERC1155/Data/ERC1155DataFacet.sol" + }, + "ERC1155ApproveFacet": { + "path": "@perfect-abstractions/compose/token/ERC1155/Approve/ERC1155ApproveFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC1155/Approve/ERC1155ApproveMod.sol" + }, + "ERC1155TransferFacet": { + "path": "@perfect-abstractions/compose/token/ERC1155/Transfer/ERC1155TransferFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC1155/Transfer/ERC1155TransferMod.sol" + } + }, + "optional": { + "ERC1155BurnFacet": { + "path": "@perfect-abstractions/compose/token/ERC1155/Burn/ERC1155BurnFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC1155/Burn/ERC1155BurnMod.sol" + }, + "ERC1155MetadataFacet": { + "path": "@perfect-abstractions/compose/token/ERC1155/Metadata/ERC1155MetadataFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC1155/Metadata/ERC1155MetadataMod.sol", + "constructor": [ + { + "comments": [ + "TODO: Review the sample ERC-1155 metadata URI before deployment." + ], + "code": "ERC1155MetadataMod.setURI(\"https://example.com/metadata/{id}.json\");" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC1155Metadata_URI.sol", + "id": "type(IERC1155Metadata_URI).interfaceId", + "comments": [ + "Register ERC-1155 metadata URI interface support." + ] + } + }, + "RoyaltyFacet": { + "path": "@perfect-abstractions/compose/token/Royalty/RoyaltyFacet.sol", + "mod": "@perfect-abstractions/compose/token/Royalty/RoyaltyMod.sol", + "constructor": [ + { + "comments": [ + "TODO: Replace the sample royalty receiver and fee before deployment." + ], + "code": "RoyaltyMod.setDefaultRoyalty(0x0000000000000000000000000000000000000001, 500);" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC2981.sol", + "id": "type(IERC2981).interfaceId", + "comments": [ + "Register ERC-2981 royalty interface support." + ] + } + } + } + } +} diff --git a/cli/bases/erc20.json b/cli/bases/erc20.json new file mode 100644 index 00000000..4650aa89 --- /dev/null +++ b/cli/bases/erc20.json @@ -0,0 +1,45 @@ +{ + "erc-20": { + "label": "ERC-20", + "order": 2, + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC20.sol", + "id": "type(IERC20).interfaceId", + "comments": ["Register ERC-20 interface support."] + }, + "required": { + "ERC20DataFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Data/ERC20DataFacet.sol" + }, + "ERC20ApproveFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Approve/ERC20ApproveFacet.sol" + }, + "ERC20TransferFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Transfer/ERC20TransferFacet.sol" + } + }, + "optional": { + "ERC20BurnFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Burn/ERC20BurnFacet.sol" + }, + "ERC20MetadataFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Metadata/ERC20MetadataFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC20/Metadata/ERC20MetadataMod.sol", + "constructor": [ + { + "comments": [ + "TODO: Review the sample token name, symbol, and decimals before deployment." + ], + "code": "ERC20MetadataMod.setMetadata({_name: \"ExampleToken\", _symbol: \"EXT\", _decimals: 18});" + } + ] + }, + "ERC20PermitFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Permit/ERC20PermitFacet.sol" + }, + "ERC20BridgeableFacet": { + "path": "@perfect-abstractions/compose/token/ERC20/Bridgeable/ERC20BridgeableFacet.sol" + } + } + } +} diff --git a/cli/bases/erc6909.json b/cli/bases/erc6909.json new file mode 100644 index 00000000..03c0b2a1 --- /dev/null +++ b/cli/bases/erc6909.json @@ -0,0 +1,49 @@ +{ + "erc-6909": { + "label": "ERC-6909", + "order": 6, + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC6909.sol", + "id": "type(IERC6909).interfaceId", + "comments": ["Register ERC-6909 interface support."] + }, + "required": { + "ERC6909DataFacet": { + "path": "@perfect-abstractions/compose/token/ERC6909/Data/ERC6909DataFacet.sol" + }, + "ERC6909TransferFacet": { + "path": "@perfect-abstractions/compose/token/ERC6909/Transfer/ERC6909TransferFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC6909/Transfer/ERC6909TransferMod.sol" + }, + "ERC6909ApproveFacet": { + "path": "@perfect-abstractions/compose/token/ERC6909/Approve/ERC6909ApproveFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC6909/Approve/ERC6909ApproveMod.sol" + }, + "ERC6909OperatorFacet": { + "path": "@perfect-abstractions/compose/token/ERC6909/Operator/ERC6909OperatorFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC6909/Operator/ERC6909OperatorMod.sol" + } + }, + "optional": { + "ERC6909BurnFacet": { + "path": "@perfect-abstractions/compose/token/ERC6909/Burn/ERC6909BurnFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC6909/Burn/ERC6909BurnMod.sol" + }, + "RoyaltyFacet": { + "path": "@perfect-abstractions/compose/token/Royalty/RoyaltyFacet.sol", + "mod": "@perfect-abstractions/compose/token/Royalty/RoyaltyMod.sol", + "constructor": [ + { + "comments": ["TODO: Replace the sample royalty receiver and fee before deployment."], + "code": "RoyaltyMod.setDefaultRoyalty(0x0000000000000000000000000000000000000001, 500);" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC2981.sol", + "id": "type(IERC2981).interfaceId", + "comments": ["Register ERC-2981 royalty interface support."] + } + } + } + } +} diff --git a/cli/bases/erc721.json b/cli/bases/erc721.json new file mode 100644 index 00000000..6af2be94 --- /dev/null +++ b/cli/bases/erc721.json @@ -0,0 +1,115 @@ +{ + "erc-721": { + "label": "ERC-721", + "order": 3, + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC721.sol", + "id": "type(IERC721).interfaceId", + "comments": ["Register ERC-721 interface support."] + }, + "required": { + "ERC721ApproveFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Approve/ERC721ApproveFacet.sol" + }, + "ERC721DataFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Data/ERC721DataFacet.sol" + }, + "ERC721TransferFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Transfer/ERC721TransferFacet.sol" + } + }, + "optional": { + "ERC721BurnFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Burn/ERC721BurnFacet.sol" + }, + "ERC721MetadataFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Metadata/ERC721MetadataFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC721/Metadata/ERC721MetadataMod.sol", + "constructor": [ + { + "comments": ["TODO: Review the sample collection name, symbol, and base URI before deployment."], + "code": "ERC721MetadataMod.setMetadata({_name: \"ExampleDiamondNFT\", _symbol: \"EDN\", _baseURI: \"https://example.com/metadata/\"});" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC721Metadata.sol", + "id": "type(IERC721Metadata).interfaceId", + "comments": ["Register ERC-721 Metadata interface support."] + } + }, + "RoyaltyFacet": { + "path": "@perfect-abstractions/compose/token/Royalty/RoyaltyFacet.sol", + "mod": "@perfect-abstractions/compose/token/Royalty/RoyaltyMod.sol", + "constructor": [ + { + "comments": ["TODO: Replace the sample royalty receiver and fee before deployment."], + "code": "RoyaltyMod.setDefaultRoyalty(0x0000000000000000000000000000000000000001, 500);" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC2981.sol", + "id": "type(IERC2981).interfaceId", + "comments": ["Register ERC-2981 royalty interface support."] + } + } + } + }, + "erc-721-enumerable": { + "label": "ERC-721 Enumerable", + "order": 4, + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC721.sol", + "id": "type(IERC721).interfaceId", + "comments": ["Register ERC-721 interface support."] + }, + "required": { + "ERC721ApproveFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Approve/ERC721ApproveFacet.sol" + }, + "ERC721DataFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Data/ERC721DataFacet.sol" + }, + "ERC721EnumerableDataFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Enumerable/Data/ERC721EnumerableDataFacet.sol" + }, + "ERC721EnumerableTransferFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Enumerable/Transfer/ERC721EnumerableTransferFacet.sol" + } + }, + "optional": { + "ERC721EnumerableBurnFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Enumerable/Burn/ERC721EnumerableBurnFacet.sol" + }, + "ERC721MetadataFacet": { + "path": "@perfect-abstractions/compose/token/ERC721/Metadata/ERC721MetadataFacet.sol", + "mod": "@perfect-abstractions/compose/token/ERC721/Metadata/ERC721MetadataMod.sol", + "constructor": [ + { + "comments": ["TODO: Review the sample collection name, symbol, and base URI before deployment."], + "code": "ERC721MetadataMod.setMetadata({_name: \"ExampleDiamondNFT\", _symbol: \"EDN\", _baseURI: \"https://example.com/metadata/\"});" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC721Metadata.sol", + "id": "type(IERC721Metadata).interfaceId", + "comments": ["Register ERC-721 Metadata interface support."] + } + }, + "RoyaltyFacet": { + "path": "@perfect-abstractions/compose/token/Royalty/RoyaltyFacet.sol", + "mod": "@perfect-abstractions/compose/token/Royalty/RoyaltyMod.sol", + "constructor": [ + { + "comments": ["TODO: Replace the sample royalty receiver and fee before deployment."], + "code": "RoyaltyMod.setDefaultRoyalty(0x0000000000000000000000000000000000000001, 500);" + } + ], + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC2981.sol", + "id": "type(IERC2981).interfaceId", + "comments": ["Register ERC-2981 royalty interface support."] + } + } + } + } +} diff --git a/cli/bases/libraries.json b/cli/bases/libraries.json new file mode 100644 index 00000000..1997572f --- /dev/null +++ b/cli/bases/libraries.json @@ -0,0 +1,11 @@ +{ + "libraries": { + "label": "Libraries", + "required": {}, + "optional": { + "ERC165Facet": { + "path": "@perfect-abstractions/compose/interfaceDetection/ERC165/ERC165Facet.sol" + } + } + } +} diff --git a/cli/bases/owner.json b/cli/bases/owner.json new file mode 100644 index 00000000..da6b5495 --- /dev/null +++ b/cli/bases/owner.json @@ -0,0 +1,67 @@ +{ + "owner": { + "label": "Owner", + "order": 7, + "access": true, + "accessType": "ownership", + "erc165": { + "path": "@perfect-abstractions/compose/interfaces/IERC173.sol", + "id": "type(IERC173).interfaceId", + "comments": ["Register ERC-173 ownership interface support."] + }, + "required": { + "OwnerDataFacet": { + "path": "@perfect-abstractions/compose/access/Owner/Data/OwnerDataFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol", + "constructor": [ + { + "comments": ["TODO: Review the initial owner policy before deployment."], + "code": "OwnerDataMod.setContractOwner(msg.sender);" + } + ] + }, + "OwnerTransferFacet": { + "path": "@perfect-abstractions/compose/access/Owner/Transfer/OwnerTransferFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/Transfer/OwnerTransferMod.sol" + } + }, + "optional": { + "OwnerRenounceFacet": { + "path": "@perfect-abstractions/compose/access/Owner/Renounce/OwnerRenounceFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/Renounce/OwnerRenounceMod.sol" + } + } + }, + "owner-two-step": { + "label": "Owner Two-Step", + "order": 8, + "access": true, + "accessType": "ownership", + "required": { + "OwnerDataFacet": { + "path": "@perfect-abstractions/compose/access/Owner/Data/OwnerDataFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol", + "constructor": [ + { + "comments": ["TODO: Review the initial owner policy before deployment."], + "code": "OwnerDataMod.setContractOwner(msg.sender);" + } + ] + }, + "OwnerTwoStepDataFacet": { + "path": "@perfect-abstractions/compose/access/Owner/TwoSteps/Data/OwnerTwoStepDataFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/TwoSteps/Data/OwnerTwoStepDataMod.sol" + }, + "OwnerTwoStepTransferFacet": { + "path": "@perfect-abstractions/compose/access/Owner/TwoSteps/Transfer/OwnerTwoStepTransferFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/TwoSteps/Transfer/OwnerTwoStepTransferMod.sol" + } + }, + "optional": { + "OwnerTwoStepRenounceFacet": { + "path": "@perfect-abstractions/compose/access/Owner/TwoSteps/Renounce/OwnerTwoStepRenounceFacet.sol", + "mod": "@perfect-abstractions/compose/access/Owner/TwoSteps/Renounce/OwnerTwoStepRenounceMod.sol" + } + } + } +} diff --git a/cli/bin/compose.js b/cli/bin/compose.js index 633e820d..b3a7f9f7 100755 --- a/cli/bin/compose.js +++ b/cli/bin/compose.js @@ -1,3 +1,3 @@ #!/usr/bin/env node -require("../index.js"); +require("../dist/index.js"); diff --git a/cli/eslint.config.js b/cli/eslint.config.js index 95840019..485869a6 100644 --- a/cli/eslint.config.js +++ b/cli/eslint.config.js @@ -1,8 +1,9 @@ const js = require("@eslint/js"); +const tseslint = require("typescript-eslint"); module.exports = [ { - ignores: ["node_modules/**", "src/templates/**"], + ignores: ["node_modules/**", "dist/**", "src/templates/**"], }, js.configs.recommended, { @@ -22,4 +23,31 @@ module.exports = [ "no-unused-vars": ["error", { argsIgnorePattern: "^_" }], }, }, + ...tseslint.configs.recommended.map((config) => ({ + ...config, + files: ["**/*.ts"], + })), + { + files: ["**/*.ts"], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + globals: { + console: "readonly", + process: "readonly", + __dirname: "readonly", + require: "readonly", + module: "readonly", + }, + }, + rules: { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-require-imports": "off", + }, + }, ]; diff --git a/cli/index.js b/cli/index.js deleted file mode 100755 index ca16455d..00000000 --- a/cli/index.js +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env node - -const minimist = require("minimist"); -const pkg = require("./package.json"); -const { logger } = require("./src/utils/logger"); -const { exitWithError } = require("./src/utils/errors"); -const { runInitCommand } = require("./src/commands/init"); -const { runVersionCommand } = require("./src/commands/version"); -const { runUpdateCommand } = require("./src/commands/update"); -const { runListTemplatesCommand } = require("./src/commands/listTemplates"); -const { HELP_TEXT } = require("./src/utils/helpText"); - -async function main() { - const argv = minimist(process.argv.slice(2), { - alias: { - v: "version", - h: "help", - n: "name", - }, - boolean: ["version", "help", "yes"], - string: ["name", "template", "framework", "language"], - }); - - const [command = ""] = argv._; - - if (argv.version) { - runVersionCommand(pkg.version); - return; - } - - if (argv.help || !command) { - logger.plain(HELP_TEXT.trim()); - return; - } - - if (command === "init") { - await runInitCommand(argv); - return; - } - - if (command === "update") { - await runUpdateCommand(pkg.name); - return; - } - - if (command === "templates") { - await runListTemplatesCommand(); - return; - } - - throw new Error(`Unknown command: ${command}. Run 'compose --help' for available commands.`); -} - -main().catch((error) => { - exitWithError(error); -}); diff --git a/cli/package.json b/cli/package.json index 3ecd3e24..0ba1062c 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,19 +1,18 @@ { "name": "@perfect-abstractions/compose-cli", - "version": "0.0.5", + "version": "0.1.0", "description": "CLI to scaffold Compose facet-based diamond projects", - "main": "index.js", + "main": "dist/index.js", "bin": { "compose": "bin/compose.js" }, "type": "commonjs", "scripts": { + "build": "tsc -p tsconfig.json", + "start": "node dist/index.js", + "dev": "tsx src/index.ts", "lint": "eslint .", - "test": "node --test \"test/**/*.test.js\"", - "test:unit": "node --test \"test/unit/**/*.test.js\"", - "test:integration": "node --test \"test/integration/**/*.test.js\"", - "check": "npm run lint && npm run test", - "build:templates": "node scripts/generate-templates-config.js", + "check": "npm run lint", "pack:check": "npm pack --dry-run", "prepublishOnly": "npm run check && npm run pack:check", "prepare:lib": "git submodule update --init --recursive" @@ -22,36 +21,28 @@ "node": ">=20" }, "files": [ - "index.js", - "src/", - "!src/templates/**/lib/", + "dist/", + "bases/", + "src/templates/", "README.md", "LICENSE.md" ], "dependencies": { + "@perfect-abstractions/compose": "0.0.4", + "@inquirer/prompts": "^8.5.2", + "commander": "^13.1.0", "fs-extra": "^11.3.3", "inquirer": "^13.3.0", - "minimist": "^1.2.8", - "picocolors": "^1.1.1" + "picocolors": "^1.1.1", + "viem": "^2.52.2" }, "devDependencies": { "@eslint/js": "^10.0.1", - "@nomicfoundation/hardhat-ethers": "^4.0.5", - "@nomicfoundation/hardhat-ignition": "^3.0.8", - "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3", - "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2", - "@types/chai": "^5.2.3", - "@types/chai-as-promised": "^8.0.2", - "@types/mocha": "^10.0.10", "@types/node": "^22.19.13", - "chai": "^6.2.2", "eslint": "^10.1.0", - "ethers": "^6.16.0", - "forge-std": "github:foundry-rs/forge-std#v1.9.4", - "hardhat": "^3.1.10", - "mocha": "^11.7.5", + "tsx": "^4.19.1", "typescript": "~5.8.0", - "viem": "^2.47.0" + "typescript-eslint": "^8.0.0" }, "keywords": [ "solidity", @@ -74,4 +65,4 @@ "bugs": { "url": "https://github.com/Perfect-Abstractions/Compose/issues" } -} \ No newline at end of file +} diff --git a/cli/scripts/generate-templates-config.js b/cli/scripts/generate-templates-config.js deleted file mode 100644 index b807b7d7..00000000 --- a/cli/scripts/generate-templates-config.js +++ /dev/null @@ -1,142 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const { validateTemplatesConfig } = require("../src/config/validateTemplatesConfig"); - -const ROOT_DIR = path.resolve(__dirname, ".."); -const TEMPLATES_ROOT = path.join(ROOT_DIR, "src", "templates"); -const OUTPUT_CONFIG_PATH = path.join(ROOT_DIR, "src", "config", "templates.json"); - -function readJsonFile(filePath) { - const content = fs.readFileSync(filePath, "utf8"); - return JSON.parse(content); -} - -function parseVariantId(templateId, variantId) { - const suffix = variantId.startsWith(`${templateId}-`) - ? variantId.slice(templateId.length + 1) - : variantId; - - const [framework, ...rest] = suffix.split("-"); - - return { - framework, - projectType: rest.length > 0 ? rest.join("-") : undefined, - }; -} - -function inferLanguageFromPath(relativePath) { - if (relativePath.includes("/ts/")) { - return "typescript"; - } - - if (relativePath.includes("/js/")) { - return "javascript"; - } - - return undefined; -} - -function buildVariantPath(templateId, framework, projectType, overridePath) { - if (overridePath) { - return overridePath; - } - - if (framework === "foundry") { - return `templates/${templateId}/${framework}`; - } - - if (!projectType) { - return `templates/${templateId}/${framework}`; - } - - return `templates/${templateId}/${framework}/ts/${projectType}`; -} - -function loadTemplateManifests() { - const entries = fs.readdirSync(TEMPLATES_ROOT, { withFileTypes: true }); - const templates = []; - - entries.forEach((entry) => { - if (!entry.isDirectory()) { - return; - } - - const templateDir = path.join(TEMPLATES_ROOT, entry.name); - const manifestPath = path.join(templateDir, "template.json"); - - if (!fs.existsSync(manifestPath)) { - return; - } - - const manifest = readJsonFile(manifestPath); - templates.push(manifest); - }); - - return templates; -} - -function buildTemplatesConfig() { - const templateManifests = loadTemplateManifests(); - - const templates = templateManifests.map((manifest) => { - const templateId = manifest.id; - - const variants = (manifest.variants || []).map((variantId) => { - const { framework, projectType } = parseVariantId(templateId, variantId); - - const pathValue = buildVariantPath( - templateId, - framework, - projectType, - ); - - const language = inferLanguageFromPath(pathValue); - - return { - id: variantId, - framework, - path: pathValue, - ...(language ? { language } : {}), - ...(projectType ? { projectType } : {}), - }; - }); - - return { - id: templateId, - name: manifest.name, - description: manifest.description, - variants, - }; - }); - - const config = { - templates, - defaultTemplateId: templateManifests[0] ? templateManifests[0].id : "default", - }; - - validateTemplatesConfig(config); - - return config; -} - -function writeTemplatesConfig(config) { - const json = `${JSON.stringify(config, null, 2)}\n`; - fs.writeFileSync(OUTPUT_CONFIG_PATH, json, "utf8"); -} - -function main() { - try { - const config = buildTemplatesConfig(); - writeTemplatesConfig(config); - console.log(`Generated templates config at ${path.relative(ROOT_DIR, OUTPUT_CONFIG_PATH)}`); - } catch (error) { - console.error("Failed to generate templates config:"); - console.error(error.message || error); - process.exitCode = 1; - } -} - -if (require.main === module) { - main(); -} - diff --git a/cli/src/adapters/foundryAdapter.ts b/cli/src/adapters/foundryAdapter.ts new file mode 100644 index 00000000..fe7bc9aa --- /dev/null +++ b/cli/src/adapters/foundryAdapter.ts @@ -0,0 +1,115 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../context/types"; +import { ConfigOptions, IFrameworkAdapter } from "./interface/IFrameworkAdapter"; +import { writeFileIfMissing } from "../utils/files"; +import { runCommand } from "../utils/exec"; +import { resolveCatalogSourceForRead } from "../utils/soliditySources"; + +function ensureTomlSectionSettings( + content: string, + section: string, + settings: Record, +): string { + const lines = content.replace(/\r\n/g, "\n").split("\n"); + if (lines.at(-1) === "") lines.pop(); + + let sectionIndex = lines.findIndex((line) => line.trim() === `[${section}]`); + if (sectionIndex === -1) { + if (lines.length > 0 && lines.at(-1)?.trim() !== "") lines.push(""); + sectionIndex = lines.length; + lines.push(`[${section}]`); + } + + let sectionEnd = lines.findIndex( + (line, index) => index > sectionIndex && /^\s*\[[^\]]+\]\s*$/.test(line), + ); + if (sectionEnd === -1) sectionEnd = lines.length; + + const sectionLines = lines.slice(sectionIndex + 1, sectionEnd); + const missingSettings = Object.entries(settings) + .filter(([key]) => !sectionLines.some((line) => new RegExp(`^\\s*${key}\\s*=`).test(line))) + .map(([key, value]) => `${key} = ${value}`); + + lines.splice(sectionEnd, 0, ...missingSettings); + return `${lines.join("\n")}\n`; +} + +/** Framework adapter for Foundry-based Diamond projects. */ +const adapter: IFrameworkAdapter = { + getContractSourceRoot(projectRoot: string): string { + return path.join(projectRoot, "src"); + }, + + getScriptRoot(projectRoot: string): string { + return path.join(projectRoot, "script"); + }, + + getTestRoot(projectRoot: string): string { + return path.join(projectRoot, "test"); + }, + + async resolveSoliditySourcePath(ctx: ComposeContext, sourcePath: string): Promise { + return resolveCatalogSourceForRead(sourcePath); + }, + + async initProject(ctx: ComposeContext): Promise { + const root = String(ctx.param.projectRoot ?? ""); + const installDeps = ctx.param.installDeps !== false; + + await runCommand("forge", ["init", "."], { cwd: root }); + + if (installDeps) { + await runCommand("forge", ["install", "Perfect-Abstractions/Compose"], { cwd: root }); + } else { + await fs.mkdir(path.join(root, "lib"), { recursive: true }); + } + + await Promise.all([ + fs.rm(path.join(root, "src"), { recursive: true, force: true }), + fs.rm(path.join(root, "test"), { recursive: true, force: true }), + fs.rm(path.join(root, "script"), { recursive: true, force: true }), + ]); + + await fs.mkdir(path.join(root, "test"), { recursive: true }); + await fs.mkdir(path.join(root, "script"), { recursive: true }); + }, + + async writeConfig(ctx: ComposeContext, opts: ConfigOptions): Promise { + const root = String(ctx.param.projectRoot ?? ""); + + const foundryTomlPath = path.join(root, "foundry.toml"); + let foundryToml = ""; + try { + foundryToml = await fs.readFile(foundryTomlPath, "utf8"); + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error; + } + + const updatedFoundryToml = ensureTomlSectionSettings(foundryToml, "profile.default", { + solc: `"${opts.compilerVersion}"`, + optimizer: "true", + }); + + const remappings = "@perfect-abstractions/compose/=lib/Compose/src/\n"; + const gitignore = "out/\ncache/\n"; + + let readme: string; + try { + const templatePath = path.resolve(process.cwd(), "src/templates/readme/foundry-readme.md"); + const template = await fs.readFile(templatePath, "utf8"); + readme = template.replace(/\{\{PROJECT_NAME\}\}/g, opts.projectName); + } catch { + readme = `# ${opts.projectName}\n\nGenerated by compose init\n`; + } + + if (updatedFoundryToml !== foundryToml) { + await fs.writeFile(foundryTomlPath, updatedFoundryToml, "utf8"); + } + await writeFileIfMissing(path.join(root, "remappings.txt"), remappings); + await writeFileIfMissing(path.join(root, ".gitignore"), gitignore); + await fs.writeFile(path.join(root, "README.md"), readme, "utf8"); + }, +}; + +export const foundryAdapter = adapter; diff --git a/cli/src/adapters/hardhatAdapter.ts b/cli/src/adapters/hardhatAdapter.ts new file mode 100644 index 00000000..3c156658 --- /dev/null +++ b/cli/src/adapters/hardhatAdapter.ts @@ -0,0 +1,165 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../context/types"; +import { ConfigOptions, IFrameworkAdapter } from "./interface/IFrameworkAdapter"; +import { writeFileIfMissing } from "../utils/files"; +import { runCommand } from "../utils/exec"; +import { isComposePackagePath, resolveCatalogSourceForRead } from "../utils/soliditySources"; +import { getSelectedFacets } from "../modules/scaffolding/module"; + +/** Framework adapter for Hardhat-based Diamond projects. */ +const adapter: IFrameworkAdapter = { + getContractSourceRoot(projectRoot: string): string { + return path.join(projectRoot, "contracts"); + }, + + getScriptRoot(projectRoot: string): string { + return path.join(projectRoot, "scripts"); + }, + + getTestRoot(projectRoot: string): string { + return path.join(projectRoot, "test"); + }, + + async resolveSoliditySourcePath(ctx: ComposeContext, sourcePath: string): Promise { + return resolveCatalogSourceForRead(sourcePath); + }, + + async initProject(ctx: ComposeContext): Promise { + const root = String(ctx.param.projectRoot ?? ""); + const projectName = String(ctx.param.projectName ?? "my-diamond"); + const toolbox = String(ctx.param.toolbox ?? "ethers"); + + const devDeps: Record = + toolbox === "viem" + ? { + hardhat: "^3.8.0", + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.0", + } + : { + hardhat: "^3.8.0", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.0", + }; + + const packageJson = { + name: projectName, + version: "0.1.0", + description: "Diamond project generated by Compose CLI", + type: "module", + main: "index.js", + scripts: { + build: "npx hardhat compile", + test: "npx hardhat test", + }, + keywords: ["solidity", "ethereum", "smart-contracts", "diamonds", "ERC-2535"], + author: "", + license: "MIT", + dependencies: { + "@perfect-abstractions/compose": "latest", + }, + devDependencies: devDeps, + }; + + await fs.writeFile(path.join(root, "package.json"), JSON.stringify(packageJson, null, 2)); + }, + + async writeConfig(ctx: ComposeContext, opts: ConfigOptions): Promise { + const root = String(ctx.param.projectRoot ?? ""); + const toolbox = String(ctx.param.toolbox ?? "ethers"); + const selectedFacets = getSelectedFacets(ctx); + const packageFacetPaths = selectedFacets + .map((facet) => facet.entry.path) + .filter(isComposePackagePath); + + const npmFilesToBuild = packageFacetPaths.length > 0 + ? ` npmFilesToBuild: ${JSON.stringify(packageFacetPaths, null, 4).replace(/\n/g, "\n ")},\n` + : ""; + + const toolboxImport = + toolbox === "viem" + ? `import hardhatToolboxViem from "@nomicfoundation/hardhat-toolbox-viem";` + : `import hardhatToolboxMochaEthers from "@nomicfoundation/hardhat-toolbox-mocha-ethers";`; + const toolboxPlugin = toolbox === "viem" ? "hardhatToolboxViem" : "hardhatToolboxMochaEthers"; + + const hardhatConfig = `import { defineConfig } from "hardhat/config"; +${toolboxImport} + +export default defineConfig({ + plugins: [${toolboxPlugin}], + solidity: { +${npmFilesToBuild} profiles: { + default: { + version: "${opts.compilerVersion}", + settings: { + optimizer: { + enabled: true, + }, + }, + }, + production: { + version: "${opts.compilerVersion}", + settings: { + optimizer: { + enabled: true, + }, + }, + }, + }, + }, + paths: { + sources: "./contracts", + tests: "./test", + cache: "./cache", + artifacts: "./artifacts", + }, +}); +`; + + await fs.writeFile(path.join(root, "hardhat.config.ts"), hardhatConfig); + + const tsconfig = `{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./contracts", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["contracts/**/*.ts"], + "exclude": ["node_modules", "dist"] +}`; + + await fs.writeFile(path.join(root, "tsconfig.json"), tsconfig); + + const gitignore = `node_modules/ +.cache/ +artifacts/ +dist/ +.env +`; + + await fs.writeFile(path.join(root, ".gitignore"), gitignore); + + let readme: string; + try { + const templatePath = path.resolve(process.cwd(), "src/templates/readme/hardhat-readme.md"); + const template = await fs.readFile(templatePath, "utf8"); + readme = template.replace(/\{\{PROJECT_NAME\}\}/g, opts.projectName); + } catch { + readme = `# ${opts.projectName}\n\nGenerated by compose init\n`; + } + await writeFileIfMissing(path.join(root, "README.md"), readme); + + await fs.mkdir(path.join(root, "test"), { recursive: true }); + + if (opts.installDeps) { + await runCommand("npm", ["install"], { cwd: root }); + } + }, +}; + +export const hardhatAdapter = adapter; diff --git a/cli/src/adapters/hashingAdapter.ts b/cli/src/adapters/hashingAdapter.ts new file mode 100644 index 00000000..3ca2626a --- /dev/null +++ b/cli/src/adapters/hashingAdapter.ts @@ -0,0 +1,10 @@ +import { keccak256, stringToBytes, type Hex } from "viem"; +import { IHashingAdapter } from "./interface/IHashingAdapter"; + +/** Adapter providing keccak256 hashing over UTF-8 strings, returning a hex digest. */ +export const HashingAdapter: IHashingAdapter = { + /** @inheritdoc */ + keccak256(value: string): Hex { + return keccak256(stringToBytes(value)); + }, +}; diff --git a/cli/src/adapters/interface/IFrameworkAdapter.ts b/cli/src/adapters/interface/IFrameworkAdapter.ts new file mode 100644 index 00000000..f6b44a04 --- /dev/null +++ b/cli/src/adapters/interface/IFrameworkAdapter.ts @@ -0,0 +1,40 @@ +import { ComposeContext } from "../../context/types"; + +/** Options passed to adapter config writing. */ +export type ConfigOptions = { + compilerVersion: string; + projectName: string; + installDeps: boolean; +}; + +/** Interface for framework-specific project scaffolding adapters. */ +export interface IFrameworkAdapter { + /** Resolve the framework's Solidity source root inside the generated project. */ + getContractSourceRoot(projectRoot: string): string; + + /** Resolve the framework's deploy script root inside the generated project. */ + getScriptRoot(projectRoot: string): string; + + /** Resolve the framework's test root inside the generated project. */ + getTestRoot(projectRoot: string): string; + + /** + * Resolve a catalog Solidity path to a readable local file. + * + * Package paths resolve from the CLI's own node_modules/@perfect-abstractions/compose/. + * Local paths resolve from the CLI's src/templates/ directory. + */ + resolveSoliditySourcePath(ctx: ComposeContext, sourcePath: string): Promise; + + /** + * Initialize the project scaffold (e.g., run `forge init`, create `package.json`). + * Called before facet files are copied. + */ + initProject(ctx: ComposeContext): Promise; + + /** + * Write framework-specific configuration files (e.g., foundry.toml, hardhat.config.ts). + * Called after facets are copied. + */ + writeConfig(ctx: ComposeContext, opts: ConfigOptions): Promise; +} diff --git a/cli/src/adapters/interface/IHashingAdapter.ts b/cli/src/adapters/interface/IHashingAdapter.ts new file mode 100644 index 00000000..c3d997a7 --- /dev/null +++ b/cli/src/adapters/interface/IHashingAdapter.ts @@ -0,0 +1,12 @@ +import { type Hex } from "viem"; + +/** Interface for hashing utilities */ +export interface IHashingAdapter { + /** + * Hashes a UTF-8 string using keccak256 and returns the hex-encoded result. + * + * @param value - The UTF-8 string to hash + * @returns The keccak256 hex digest + */ + keccak256(value: string): Hex; +} \ No newline at end of file diff --git a/cli/src/comander.ts b/cli/src/comander.ts new file mode 100644 index 00000000..690e4155 --- /dev/null +++ b/cli/src/comander.ts @@ -0,0 +1,75 @@ +import { Command } from "commander"; +import { VERSION } from "./utils/metadata"; + +/** + * Defines the CLI program with per-command flags. + * + * Commander handles argument parsing, unknown flag rejection, + * auto-generated --help per command, and --version. + */ +export function buildProgram(): Command { + const program = new Command() + .name("compose") + .version(VERSION) + .description("Multi-Facets Diamond project toolkit powered by Compose") + .allowUnknownOption(false); + + program + .command("init") + .description("Scaffold a new Compose diamond project") + .argument("[project-name]", "Project name") + .option("--framework ", "Framework to use", "foundry") + .option("--base ", "Base preset (e.g. erc-20, counter)") + .option("--libraries ", "Comma-separated library facets") + .option("--extensions ", "Comma-separated extension facets") + .option("--ownership ", "Ownership access base") + .option("--ownership-extensions ", "Ownership extension facets") + .option("--access-control ", "Comma-separated access control bases") + .option("--access-control-extensions ", "Access control extension facets") + .option("--out ", "Output directory") + .option("--yes", "Non-interactive mode (requires --base)") + .option("--install-deps", "Install dependencies (default)") + .option("--no-install-deps", "Skip dependency installation") + .option("--toolbox ", "Hardhat toolbox", "ethers"); + + program + .command("validate") + .description("Validate your project (Coming Soon...)") + + program + .command("info") + .description("Display a summary of the local project") + + return program; +} + +/** + * Parses CLI arguments using commander and returns a structured result. + * + * @param argv - The raw process.argv array (e.g. ["node", "cli.ts", "init", "--yes"]) + * @returns The parsed command name and flags object ready for ctx.param. + */ +export function parseArgs(argv: string[]): { command: string; flags: Record } { + const program = buildProgram(); + program.parse(argv); + + const command = program.args[0] ?? ""; + const commandInstance = program.commands.find((c) => c.name() === command); + + if (!commandInstance) { + return { command, flags: {} }; + } + + const opts = commandInstance.opts(); + const flags: Record = { ...opts }; + + // Map the first positional argument to projectName if --name wasn't passed + const positionalArgs = commandInstance.args.filter( + (arg): arg is string => typeof arg === "string" && arg !== command, + ); + if (positionalArgs.length > 0 && !flags.projectName) { + flags.projectName = positionalArgs[0]; + } + + return { command, flags }; +} diff --git a/cli/src/commands/init.js b/cli/src/commands/init.js deleted file mode 100644 index 9a57f76d..00000000 --- a/cli/src/commands/init.js +++ /dev/null @@ -1,149 +0,0 @@ -const fs = require("fs-extra"); -const path = require("node:path"); -const { askInitPrompts } = require("../prompts/initPrompts"); -const { logger } = require("../utils/logger"); -const { COMPOSE_DOCS_URL, COMPOSE_REPO_URL } = require("../config/constants"); -const { loadTemplateConfig, pickVariant, resolveTemplatePath } = require("../scaffold/utils/templateLoader"); -const { scaffold } = require("../scaffold/scaffold"); -const { COMPOSE_HEADER } = require("../utils/composeAsciiHeader"); - -function normalizeInitOptions(argv) { - const options = { - projectName: argv.name || "", - template: argv.template || "", - framework: argv.framework || "", - language: argv.language, - hardhatProjectType: argv.hardhatProjectType, - installDeps: argv["install-deps"], - yes: Boolean(argv.yes), - }; - - return options; -} - -async function ensureBinaryExists(binaryName) { - const hasPath = process.env.PATH || ""; - const separator = process.platform === "win32" ? ";" : ":"; - const paths = hasPath.split(separator); - const extensions = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]; - - for (const currentPath of paths) { - for (const extension of extensions) { - const candidate = path.join(currentPath, `${binaryName}${extension}`); - if (await fs.pathExists(candidate)) { - return true; - } - } - } - - return false; -} - -async function preflightChecks(options) { - if (options.framework === "foundry") { - const forgeExists = await ensureBinaryExists("forge"); - if (!forgeExists) { - throw new Error( - "forge not found in PATH. Please install Foundry and try again.", - ); - } - } - - if (options.framework === "hardhat" && options.installDeps !== false) { - const npmExists = await ensureBinaryExists("npm"); - if (!npmExists) { - throw new Error("npm not found in PATH. Please install Node.js (with npm) and try again."); - } - } -} - -async function collectInitOptions(argv) { - const normalized = normalizeInitOptions(argv); - - if (normalized.yes) { - if (!normalized.projectName) { - normalized.projectName = "my-diamond"; - } - if (typeof normalized.installDeps !== "boolean") { - normalized.installDeps = true; - } - return normalized; - } - - const answers = await askInitPrompts({ - name: normalized.projectName || undefined, - template: normalized.template || undefined, - framework: normalized.framework || undefined, - hardhatProjectType: normalized.hardhatProjectType, - installDeps: normalized.installDeps, - }); - - const framework = answers.framework || normalized.framework; - const language = - normalized.language || (framework === "hardhat" ? "typescript" : normalized.language); - - return { - ...normalized, - projectName: answers.name || normalized.projectName || "my-diamond", - template: answers.template || normalized.template, - framework, - language, - hardhatProjectType: answers.hardhatProjectType || normalized.hardhatProjectType, - installDeps: typeof answers.installDeps === "boolean" ? answers.installDeps : true, - }; -} - -function printInitHeader() { - logger.info(COMPOSE_HEADER); - logger.info("Scaffold your diamond smart contracts project with Compose"); - logger.info(`Explore our library: ${COMPOSE_DOCS_URL}\n`); -} - -async function runInitCommand(argv) { - printInitHeader(); - const initOptions = await collectInitOptions(argv); - await preflightChecks(initOptions); - - const templateConfig = await loadTemplateConfig(); - const selectedVariant = pickVariant(templateConfig, { - template: initOptions.template, - framework: initOptions.framework, - language: initOptions.language, - projectType: initOptions.hardhatProjectType, - }); - - const templatePath = resolveTemplatePath(selectedVariant); - - - const { projectDir, displayName, nextSteps } = await scaffold({ - projectName: initOptions.projectName, - templatePath, - options: { - framework: selectedVariant.framework, - language: selectedVariant.language, - hardhatProjectType: initOptions.hardhatProjectType || selectedVariant.projectType, - installDeps: initOptions.installDeps, - }, - }); - - logger.success(`\nProject "${displayName}" scaffolded in "${projectDir}"`); - logger.plain("Next steps:"); - let stepCount = 1; - if (path.resolve(projectDir) !== process.cwd()) { - logger.plain(`${stepCount}. cd ${displayName}`); - } - for (const step of nextSteps) { - logger.plain(`${stepCount}. ${step}`); - stepCount++; - } - - logger.plain(""); - logger.info("You're all set. We hope you'll Compose something great!\n"); - logger.brightYellow(`If this helped you, please give us a star on GitHub:\n✨ ${COMPOSE_REPO_URL} ✨\n`); - logger.warn(`Please report any issues or feedback:\n${COMPOSE_REPO_URL}/issues\n`); -} - -module.exports = { - runInitCommand, - normalizeInitOptions, -}; diff --git a/cli/src/commands/listTemplates.js b/cli/src/commands/listTemplates.js deleted file mode 100644 index 3a3c175c..00000000 --- a/cli/src/commands/listTemplates.js +++ /dev/null @@ -1,23 +0,0 @@ -const { loadTemplateConfig } = require("../scaffold/utils/templateLoader"); -const { logger } = require("../utils/logger"); - -async function runListTemplatesCommand() { - const config = await loadTemplateConfig(); - - config.templates.forEach((template) => { - logger.plain(`${template.id} - ${template.name}`); - template.variants.forEach((variant) => { - const meta = [ - variant.framework, - variant.language, - variant.projectType, - ].filter(Boolean).join(", "); - - logger.plain(` - ${variant.id}${meta ? ` (${meta})` : ""}`); - }); - }); -} - -module.exports = { - runListTemplatesCommand, -}; diff --git a/cli/src/commands/update.js b/cli/src/commands/update.js deleted file mode 100644 index 623d0ea4..00000000 --- a/cli/src/commands/update.js +++ /dev/null @@ -1,14 +0,0 @@ -const { runCommand } = require("../utils/exec"); -const { logger } = require("../utils/logger"); - -async function runUpdateCommand(packageName) { - logger.info("Updating CLI to latest..."); - await runCommand("npm", ["install", "-g", `${packageName}@latest`], { - cwd: process.cwd(), - }); - logger.success("Update complete."); -} - -module.exports = { - runUpdateCommand, -}; diff --git a/cli/src/commands/version.js b/cli/src/commands/version.js deleted file mode 100644 index 0e4cd959..00000000 --- a/cli/src/commands/version.js +++ /dev/null @@ -1,9 +0,0 @@ -const { logger } = require("../utils/logger"); - -function runVersionCommand(version) { - logger.plain(version); -} - -module.exports = { - runVersionCommand, -}; diff --git a/cli/src/config/constants.js b/cli/src/config/constants.js deleted file mode 100644 index 26010f50..00000000 --- a/cli/src/config/constants.js +++ /dev/null @@ -1,26 +0,0 @@ -const path = require("node:path"); - -const COMPOSE_REPO_URL = "https://github.com/Perfect-Abstractions/Compose"; -const COMPOSE_DOCS_URL = "https://compose.diamonds/"; - -const COMPOSE_NPM_PACKAGE = "@perfect-abstractions/compose"; -const COMPOSE_NPM_VERSION = "latest"; - -const COMPOSE_FOUNDRY_DEP = "Perfect-Abstractions/Compose"; - -const DEFAULT_TEMPLATE_ID = "default"; -const DEFAULT_FRAMEWORK = "foundry"; - -const TEMPLATE_REGISTRY_PATH = path.join(__dirname, "templates.json"); - -module.exports = { - COMPOSE_REPO_URL, - COMPOSE_DOCS_URL, - COMPOSE_NPM_PACKAGE, - COMPOSE_NPM_VERSION, - COMPOSE_FOUNDRY_DEP, - DEFAULT_TEMPLATE_ID, - DEFAULT_FRAMEWORK, - TEMPLATE_REGISTRY_PATH, -}; - diff --git a/cli/src/config/templates.json b/cli/src/config/templates.json deleted file mode 100644 index 05f277f5..00000000 --- a/cli/src/config/templates.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "templates": [ - { - "id": "default", - "name": "Counter", - "description": "Simple diamond with a counter facet", - "variants": [ - { - "id": "default-foundry", - "framework": "foundry", - "path": "templates/default/foundry" - }, - { - "id": "default-hardhat-minimal", - "framework": "hardhat", - "path": "templates/default/hardhat/ts/minimal", - "language": "typescript", - "projectType": "minimal" - }, - { - "id": "default-hardhat-mocha-ethers", - "framework": "hardhat", - "path": "templates/default/hardhat/ts/mocha-ethers", - "language": "typescript", - "projectType": "mocha-ethers" - }, - { - "id": "default-hardhat-node-runner-viem", - "framework": "hardhat", - "path": "templates/default/hardhat/ts/node-runner-viem", - "language": "typescript", - "projectType": "node-runner-viem" - } - ] - } - ], - "defaultTemplateId": "default" -} diff --git a/cli/src/config/validateTemplatesConfig.js b/cli/src/config/validateTemplatesConfig.js deleted file mode 100644 index f155e929..00000000 --- a/cli/src/config/validateTemplatesConfig.js +++ /dev/null @@ -1,38 +0,0 @@ -function ensureString(value, keyPath) { - if (typeof value !== "string" || value.trim() === "") { - throw new Error(`Invalid templates config: ${keyPath} must be a non-empty string`); - } -} - -function validateTemplatesConfig(config) { - if (!config || typeof config !== "object") { - throw new Error("Invalid templates config: config root must be an object"); - } - - if (!Array.isArray(config.templates) || config.templates.length === 0) { - throw new Error("Invalid templates config: templates must be a non-empty array"); - } - - config.templates.forEach((template, index) => { - ensureString(template.id, `templates[${index}].id`); - ensureString(template.name, `templates[${index}].name`); - - if (!Array.isArray(template.variants) || template.variants.length === 0) { - throw new Error(`Invalid templates config: templates[${index}].variants must be a non-empty array`); - } - - template.variants.forEach((variant, variantIndex) => { - ensureString(variant.id, `templates[${index}].variants[${variantIndex}].id`); - ensureString(variant.framework, `templates[${index}].variants[${variantIndex}].framework`); - ensureString(variant.path, `templates[${index}].variants[${variantIndex}].path`); - }); - }); - - ensureString(config.defaultTemplateId, "defaultTemplateId"); - - return true; -} - -module.exports = { - validateTemplatesConfig, -}; diff --git a/cli/src/context/context.ts b/cli/src/context/context.ts new file mode 100644 index 00000000..5cddd18a --- /dev/null +++ b/cli/src/context/context.ts @@ -0,0 +1,19 @@ +import { ComposeContext } from "./types"; + + +export const Context = { + // Create a fresh command context with empty params, config, state, and successful status. + create(): ComposeContext { + return { + param: {}, + config: {}, + state: {}, + status: { + success: true, + stopped: false, + failedAt: null, + error: null, + }, + }; + }, +}; diff --git a/cli/src/context/types.ts b/cli/src/context/types.ts new file mode 100644 index 00000000..eec4b3e4 --- /dev/null +++ b/cli/src/context/types.ts @@ -0,0 +1,31 @@ +export type ComposeError = { + code: string; + message: string; + nativeError: unknown | null; +}; + +export type ModuleState = { + success: boolean; + result: T | null; + error: ComposeError | null; +}; + +export type ExecutionStatus = { + success: boolean; + stopped: boolean; + failedAt: string | null; + error: ComposeError | null; +}; + +export type ChildPipelineState = { + success: boolean; + state: Record; + status: ExecutionStatus; +}; + +export type ComposeContext = { + param: Record; + config: Record; + state: Record; + status: ExecutionStatus; +}; diff --git a/cli/src/index.ts b/cli/src/index.ts new file mode 100644 index 00000000..bb4a80f7 --- /dev/null +++ b/cli/src/index.ts @@ -0,0 +1,26 @@ +import { Context } from "./context/context"; +import { ComposeContext } from "./context/types"; +import { EntryPipeline } from "./pipelines/entryPipeline"; +import { exitWithError } from "./utils/errors"; +import { parseArgs } from "./comander"; + +/** + * Main Entrypoint for the Compose CLI + */ +async function main(): Promise { + const { command, flags } = parseArgs(process.argv); + + const ctx: ComposeContext = Context.create(); + ctx.param.command = command; + ctx.param = { ...ctx.param, ...flags }; + + try { + await EntryPipeline.execute(ctx); + } catch (error) { + exitWithError(error); + } +} + +main().catch((error: unknown) => { + exitWithError(error); +}); diff --git a/cli/src/modules/config/catalog.ts b/cli/src/modules/config/catalog.ts new file mode 100644 index 00000000..a7c837ce --- /dev/null +++ b/cli/src/modules/config/catalog.ts @@ -0,0 +1,47 @@ +import { BaseDefinition, BasesCatalog } from "./types"; + +/** Default empty base definition representing "None" with no required or optional facets. */ +export const EMPTY_BASE: BaseDefinition = { + label: "None", + required: {}, + optional: {}, +}; + +/** + * Sorts a record of base feature definitions by their `order` metadata property, + * falling back to alphabetical label comparison when orders are equal or missing. + * + * @param features - Map of feature keys to their base definitions. + * @returns A new record with entries sorted by order, then label. + */ +export function sortBaseFeatures(features: Record): Record { + return Object.fromEntries( + Object.entries(features).sort(([_, leftDef], [__, rightDef]) => { + const leftOrder = leftDef.order ?? Number.MAX_SAFE_INTEGER; + const rightOrder = rightDef.order ?? Number.MAX_SAFE_INTEGER; + + if (leftOrder !== rightOrder) { + return leftOrder - rightOrder; + } + + return leftDef.label.localeCompare(rightDef.label); + }), + ); +} + +/** + * Extracts and validates the Diamond compiler version from a bases catalog. + * The version must be an exact semantic version string (e.g. "0.8.30"). + * + * @param catalog - The bases catalog containing a globals.diamond definition. + * @returns The validated semantic version string. + * @throws {Error} If the compiler version is missing or not a valid semver string. + */ +export function getDiamondCompilerVersion(catalog: BasesCatalog): string { + const compilerVersion = catalog.globals.diamond?.compilerVersion; + if (typeof compilerVersion !== "string" || !/^\d+\.\d+\.\d+$/.test(compilerVersion)) { + throw new Error("Diamond compilerVersion must be an exact semantic version such as 0.8.30."); + } + + return compilerVersion; +} diff --git a/cli/src/modules/config/module.ts b/cli/src/modules/config/module.ts new file mode 100644 index 00000000..662c090a --- /dev/null +++ b/cli/src/modules/config/module.ts @@ -0,0 +1,75 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../../context/types"; +import { BasesCatalog, BaseDefinition, BaseManifest } from "./types"; +import { sortBaseFeatures } from "./catalog"; + +export { EMPTY_BASE, getDiamondCompilerVersion } from "./catalog"; +export { resolveCatalogSelection, getAccessBases, getAvailableLibraryFacets, validateGroupedAccessFlags } from "./selection"; + +/** + * Loads and indexes the Compose bases catalog from JSON manifest files. + * + * Reads all `.json` files from the `bases/` directory, separates entries into + * globals (diamond, libraries, examples) and feature bases, sorts features by + * standard order, and stores the result on the context. + */ +export const ConfigModule = { + /** + * Reads JSON manifest files from `bases/` and builds the {@link BasesCatalog}. + * + * Each manifest is parsed and its entries are classified: + * - Keys `diamond`, `libraries`, `examples` become globals. + * - All other keys become feature bases, sorted by Compose's standard order + * (erc-20, erc-721, etc.) then alphabetically. + * + * The catalog is stored on `ctx.config.bases` and a summary is written to + * `ctx.state.config`. + * + * @param ctx - The compose context (must have `process.cwd()` pointing to a + * directory containing a `bases/` folder). + * @returns The context with the loaded bases catalog. + */ + async loadBasesCatalog(ctx: ComposeContext): Promise { + const basesRoot = path.resolve(process.cwd(), "bases"); + const entries = await fs.readdir(basesRoot, { withFileTypes: true }); + + const globals: BasesCatalog["globals"] = {}; + const features: Record = {}; + + for (const entry of entries) { + if (!entry.isFile() || path.extname(entry.name).toLowerCase() !== ".json") { + continue; + } + + const manifestPath = path.join(basesRoot, entry.name); + const raw = await fs.readFile(manifestPath, "utf8"); + const manifest = JSON.parse(raw) as BaseManifest; + + for (const [key, definition] of Object.entries(manifest)) { + if (key === "diamond" || key === "libraries" || key === "examples") { + globals[key] = definition; + continue; + } + + features[key] = definition; + } + } + + const catalog = { globals, features: sortBaseFeatures(features) }; + + ctx.config.bases = catalog; + ctx.state.config = { + success: true, + result: { + baseCount: Object.keys(catalog.features).length, + hasDiamondCatalog: Boolean(globals.diamond), + hasLibrariesCatalog: Boolean(globals.libraries), + hasExamplesCatalog: Boolean(globals.examples), + }, + error: null, + }; + + return ctx; + }, +}; diff --git a/cli/src/modules/config/selection.ts b/cli/src/modules/config/selection.ts new file mode 100644 index 00000000..7938970e --- /dev/null +++ b/cli/src/modules/config/selection.ts @@ -0,0 +1,284 @@ +import { + BaseDefinition, + BasesCatalog, + CatalogSelection, + FacetEntry, +} from "./types"; +import { EMPTY_BASE } from "./catalog"; +import { uniqueStrings } from "../../utils/strings"; +import { isDeepEqual } from "../../utils/objects"; + +/** + * Returns all features marked as access bases, excluding the currently selected base key. + * + * @param catalog - The bases catalog to search. + * @param selectedBaseKey - The key of the currently selected base (excluded from results). + * @returns A record of feature keys to their definitions where `access === true`. + */ +export function getAccessBases( + catalog: BasesCatalog, + selectedBaseKey?: string, +): Record { + return Object.fromEntries( + Object.entries(catalog.features).filter( + ([key, definition]) => definition.access === true && key !== selectedBaseKey, + ), + ); +} + +/** + * Returns optional library facets that are not already required by the selected base + * or by global definitions. + * + * @param catalog - The bases catalog containing global definitions. + * @param selectedBase - The currently selected base definition. + * @returns A record of facet names to their entries that are available as optional libraries. + */ +export function getAvailableLibraryFacets( + catalog: BasesCatalog, + selectedBase: BaseDefinition, +): Record { + const requiredFacets = mergeFacetMaps( + catalog.globals.diamond?.required ?? {}, + catalog.globals.libraries?.required ?? {}, + selectedBase.required, + ); + + return Object.fromEntries( + [ + ...Object.entries(catalog.globals.diamond?.optional ?? {}), + ...Object.entries(catalog.globals.libraries?.optional ?? {}), + ].filter(([facetName]) => !(facetName in requiredFacets)), + ); +} + +/** + * Resolves a complete catalog selection from user inputs, validating all choices + * and computing the final set of required and available facets. + * + * @param catalog - The bases catalog containing all available features. + * @param selectedBaseKey - The key of the base to use, or "none" for an empty base. + * @param selectedLibraries - Names of global libraries to include. + * @param selectedExtensions - Names of optional base extensions to include. + * @param selectedAccessBases - Names of access control bases to layer on. + * @param selectedAccessExtensions - Names of optional access control extensions to include. + * @returns The fully resolved catalog selection with all facets computed. + * @throws {Error} If any selected key is unknown or conflicts exist. + */ +export function resolveCatalogSelection( + catalog: BasesCatalog, + selectedBaseKey: string, + selectedLibraries: string[], + selectedExtensions: string[] = [], + selectedAccessBases: string[] = [], + selectedAccessExtensions: string[] = [], +): CatalogSelection { + const selectedBase = selectedBaseKey === "none" + ? EMPTY_BASE + : catalog.features[selectedBaseKey]; + if (!selectedBase) { + throw new Error( + `Unknown base: ${selectedBaseKey}. Available: ${Object.keys(catalog.features).join(", ")}`, + ); + } + + const availableGlobalLibraryFacets = getAvailableLibraryFacets(catalog, selectedBase); + const accessBases = getAccessBases(catalog, selectedBaseKey); + const selectedGlobalLibraries: string[] = []; + const selectedAccessBaseKeys: string[] = []; + + for (const libraryName of uniqueStrings(selectedLibraries)) { + const isGlobalLibrary = libraryName in availableGlobalLibraryFacets; + if (isGlobalLibrary) { + selectedGlobalLibraries.push(libraryName); + continue; + } + + const available = Object.keys(availableGlobalLibraryFacets); + throw new Error(`Unknown library: ${libraryName}. Available: ${available.join(", ")}`); + } + + for (const accessName of uniqueStrings(selectedAccessBases)) { + if (accessName === selectedBaseKey && selectedBase.access === true) { + throw new Error( + `Base ${selectedBaseKey} is already selected and cannot also be selected as an access layer.`, + ); + } + + if (!accessBases[accessName]) { + throw new Error(`Unknown access layer: ${accessName}. Available: ${Object.keys(accessBases).join(", ")}`); + } + + selectedAccessBaseKeys.push(accessName); + } + + validateSingleOwnershipAccessBase(accessBases, selectedAccessBaseKeys); + + const accessBaseDefinitions = selectedAccessBaseKeys.map( + (key) => accessBases[key], + ); + const requiredFacets = mergeFacetMaps( + catalog.globals.diamond?.required ?? {}, + catalog.globals.libraries?.required ?? {}, + selectedBase.required, + ...accessBaseDefinitions.map((definition) => definition.required), + ); + const availableExtensions = mergeFacetMaps( + selectedBase.optional, + ); + const availableAccessExtensions = mergeFacetMaps( + ...accessBaseDefinitions.map((definition) => definition.optional), + ); + const normalizedExtensions = uniqueStrings(selectedExtensions); + const normalizedAccessExtensions = uniqueStrings(selectedAccessExtensions); + + for (const extensionName of normalizedExtensions) { + if (!availableExtensions[extensionName]) { + throw new Error( + `Unknown extension: ${extensionName}. Available: ${Object.keys(availableExtensions).join(", ")}`, + ); + } + } + + for (const extensionName of normalizedAccessExtensions) { + if (!availableAccessExtensions[extensionName]) { + throw new Error( + `Unknown access extension: ${extensionName}. Available: ${Object.keys(availableAccessExtensions).join(", ")}`, + ); + } + } + + return { + selectedBaseKey, + selectedBase, + selectedGlobalLibraries, + selectedAccessBaseKeys, + selectedAccessBases: accessBaseDefinitions, + selectedExtensions: normalizedExtensions, + selectedAccessExtensions: normalizedAccessExtensions, + requiredFacets, + availableGlobalLibraryFacets, + availableExtensions, + availableAccessExtensions, + }; +} + +/** + * Validates that grouped access flags (ownership vs role-based) are internally consistent. + * Ensures at most one ownership base is selected and that extensions belong to valid bases. + * + * @param catalog - The bases catalog containing access base definitions. + * @param selectedBaseKey - The currently selected base key (cannot also be an access layer). + * @param selectedOwnership - Names of ownership-type access bases (at most one). + * @param selectedRoleAccess - Names of role-based access bases. + * @param selectedOwnershipExtensions - Extensions to apply to the ownership base. + * @param selectedRoleAccessExtensions - Extensions to apply to role-based access bases. + * @throws {Error} If ownership count exceeds one or extensions reference invalid bases. + */ +export function validateGroupedAccessFlags( + catalog: BasesCatalog, + selectedBaseKey: string, + selectedOwnership: string[], + selectedRoleAccess: string[], + selectedOwnershipExtensions: string[], + selectedRoleAccessExtensions: string[], +): void { + const accessBases = getAccessBases(catalog, selectedBaseKey); + + if (selectedOwnership.length > 1) { + throw new Error("--ownership accepts only one ownership base."); + } + + for (const baseKey of selectedOwnership) { + if (accessBases[baseKey]?.accessType !== "ownership") { + throw new Error(`Invalid ownership base: ${baseKey}. Choose a base with accessType "ownership".`); + } + } + + for (const baseKey of selectedRoleAccess) { + if (!accessBases[baseKey] || accessBases[baseKey].accessType === "ownership") { + throw new Error(`Invalid access-control base: ${baseKey}. Choose a non-ownership access base.`); + } + } + + validateExtensionsFromBases( + selectedOwnershipExtensions, + selectedOwnership.map((baseKey) => accessBases[baseKey]), + "ownership extension", + ); + validateExtensionsFromBases( + selectedRoleAccessExtensions, + selectedRoleAccess.map((baseKey) => accessBases[baseKey]), + "access-control extension", + ); +} + +/** + * Ensures at most one ownership-type access base is selected. + * + * @param accessBases - All available access bases. + * @param selectedAccessBaseKeys - Keys of the selected access bases. + * @throws {Error} If more than one ownership base is selected. + */ +function validateSingleOwnershipAccessBase( + accessBases: Record, + selectedAccessBaseKeys: string[], +): void { + const ownershipKeys = selectedAccessBaseKeys.filter( + (key) => accessBases[key]?.accessType === "ownership", + ); + + if (ownershipKeys.length > 1) { + throw new Error( + `Access layers cannot be selected together: ${ownershipKeys.join(", ")}. Choose one ownership model.`, + ); + } +} + +/** + * Validates that all extension names exist in the optional facets of the given bases. + * + * @param extensionNames - Names of extensions to validate. + * @param bases - Base definitions whose optional facets are considered valid. + * @param label - Human-readable label for error messages (e.g. "ownership extension"). + * @throws {Error} If any extension name is not found in the bases' optional facets. + */ +function validateExtensionsFromBases( + extensionNames: string[], + bases: BaseDefinition[], + label: string, +): void { + const available = mergeFacetMaps(...bases.map((definition) => definition.optional)); + + for (const extensionName of uniqueStrings(extensionNames)) { + if (!available[extensionName]) { + throw new Error(`Unknown ${label}: ${extensionName}. Available: ${Object.keys(available).join(", ")}`); + } + } +} + +/** + * Merges multiple facet maps into one, throwing on conflicting definitions. + * Earlier maps take precedence; later entries with the same name must be identical. + * + * @param facetMaps - Facet maps to merge, in order of precedence. + * @returns A single merged facet map. + * @throws {Error} If two maps define the same facet with different entries. + */ +function mergeFacetMaps( + ...facetMaps: Record[] +): Record { + const merged: Record = {}; + + for (const facetMap of facetMaps) { + for (const [name, entry] of Object.entries(facetMap)) { + const existing = merged[name]; + if (existing && !isDeepEqual(existing, entry)) { + throw new Error(`Facet ${name} has conflicting definitions across selected bases.`); + } + merged[name] = existing ?? entry; + } + } + + return merged; +} diff --git a/cli/src/modules/config/types.ts b/cli/src/modules/config/types.ts new file mode 100644 index 00000000..2446f313 --- /dev/null +++ b/cli/src/modules/config/types.ts @@ -0,0 +1,55 @@ +export type Erc165Entry = { + path: string; + id: string; + comments?: string[]; +}; + +export type ConstructorEntry = { + comments?: string[]; + code: string; +}; + +export type FacetEntry = { + path: string; + mod?: string; + constructor?: ConstructorEntry[]; + erc165?: Erc165Entry; +}; + +export type BaseDefinition = { + label: string; + order?: number; + visible?: boolean; + access?: boolean; + accessType?: "ownership" | "roles"; + pragma?: string; + compilerVersion?: string; + erc165?: Erc165Entry; + required: Record; + optional: Record; +}; + +export type BaseManifest = Record; + +export type BasesCatalog = { + globals: { + diamond?: BaseDefinition; + libraries?: BaseDefinition; + examples?: BaseDefinition; + }; + features: Record; +}; + +export type CatalogSelection = { + selectedBaseKey: string; + selectedBase: BaseDefinition; + selectedGlobalLibraries: string[]; + selectedAccessBaseKeys: string[]; + selectedAccessBases: BaseDefinition[]; + selectedExtensions: string[]; + selectedAccessExtensions: string[]; + requiredFacets: Record; + availableGlobalLibraryFacets: Record; + availableExtensions: Record; + availableAccessExtensions: Record; +}; diff --git a/cli/src/modules/deployGeneration/model.ts b/cli/src/modules/deployGeneration/model.ts new file mode 100644 index 00000000..5eb34e88 --- /dev/null +++ b/cli/src/modules/deployGeneration/model.ts @@ -0,0 +1,97 @@ +import path from "node:path"; +import { ComposeContext, ModuleState } from "../../context/types"; +import { getSelectedFacets } from "../scaffolding/module"; +import { ScaffoldMapEntry, SelectedFacet, SelectedFacetSource } from "../scaffolding/types"; +import { DeployFacetEntry, DeployFacetGroup, DeployGenerationModel } from "./types"; +import { toPosixPath } from "../../utils/files"; + +/** + * Classifies a selected facet source into a deploy facet group. + * Base-required facets and extensions are grouped as "base"; others as "library". + * + * @param source - The source type of the selected facet. + * @returns The deploy group classification. + */ +function classifyDeployGroup(source: SelectedFacetSource): DeployFacetGroup { + if (source === "base-required" || source === "extension") { + return "base"; + } + return "library"; +} + +/** + * Extracts scaffold map entries from the compose context state. + * + * @param ctx - The compose context containing scaffold map state. + * @returns The list of scaffold map entries. + * @throws {Error} If the scaffold map is missing or in a failed state. + */ +function getScaffoldEntries(ctx: ComposeContext): ScaffoldMapEntry[] { + const state = ctx.state.scaffoldMap as ModuleState<{ entries: ScaffoldMapEntry[] }> | undefined; + if (!state?.success || !state.result) { + throw new Error("Cannot generate deploy script: scaffold map is missing."); + } + return state.result.entries; +} + +/** + * Resolves the deploy generation model by combining scaffold entries with selected facets. + * Produces ordered deploy facet entries with import paths relative to the project root, + * grouped by base facets first, then library facets. + * + * @param ctx - The compose context with project state and parameters. + * @param scriptRoot - Directory where the deploy script will be written. + * @param outputFileName - Name of the output deploy script file. + * @returns The deploy generation model with output path and ordered facet entries. + * @throws {Error} If project root, script root, or scaffold entries are invalid. + */ +export function resolveDeployGenerationModel( + ctx: ComposeContext, + scriptRoot: string, + outputFileName: string, +): DeployGenerationModel { + const projectRoot = String(ctx.param.projectRoot ?? ""); + if (!projectRoot) { + throw new Error("Cannot generate deploy script: project root is empty."); + } + if (!scriptRoot) { + throw new Error("Cannot generate deploy script: script root is empty."); + } + + const scaffoldEntries = getScaffoldEntries(ctx); + const scaffoldByFacetName = new Map(scaffoldEntries.map((entry) => [entry.facetName, entry])); + const selectedFacets = getSelectedFacets(ctx); + + const deployEntries = selectedFacets.map((facet: SelectedFacet): DeployFacetEntry => { + const scaffoldEntry = scaffoldByFacetName.get(facet.name); + if (!scaffoldEntry) { + throw new Error(`Cannot generate deploy script: scaffold entry not found for ${facet.name}.`); + } + + const importPath = scaffoldEntry.origin === "package" + ? scaffoldEntry.targetPath + : toPosixPath(path.relative(projectRoot, scaffoldEntry.targetPath)); + if (!importPath) { + throw new Error(`Cannot generate deploy script: invalid import path for ${facet.name}.`); + } + + return { + facetName: facet.name, + contractName: scaffoldEntry.contractName, + importPath, + source: facet.source, + origin: scaffoldEntry.origin, + group: classifyDeployGroup(facet.source), + }; + }); + + const facets = [ + ...deployEntries.filter((entry) => entry.group === "base"), + ...deployEntries.filter((entry) => entry.group === "library"), + ]; + + return { + outputPath: path.join(scriptRoot, outputFileName), + facets, + }; +} diff --git a/cli/src/modules/deployGeneration/module.ts b/cli/src/modules/deployGeneration/module.ts new file mode 100644 index 00000000..7a34d6ad --- /dev/null +++ b/cli/src/modules/deployGeneration/module.ts @@ -0,0 +1,65 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../../context/types"; +import { + renderFoundryDeployScript, + renderHardhatEthersDeployScript, + renderHardhatViemDeployScript, +} from "./renderers"; +import { resolveDeployGenerationModel } from "./model"; + +/** + * Module responsible for generating framework-specific deploy scripts. + */ +export const DeployGenerationModule = { + /** + * Generates a deploy script for the selected framework and toolbox, + * writes it to disk, and updates the compose context state. + * + * @param ctx - The compose context with project parameters and state. + * @param scriptRoot - Directory where the deploy script will be written. + * @returns The updated compose context with generation results. + * @throws {Error} If the framework is unsupported or file operations fail. + */ + async generateDeployScript( + ctx: ComposeContext, + scriptRoot: string, + ): Promise { + const framework = String(ctx.param.framework ?? "foundry"); + const toolbox = String(ctx.param.toolbox ?? "ethers"); + const outputFileName = framework === "foundry" ? "Deploy.s.sol" : "deploy.ts"; + const model = resolveDeployGenerationModel(ctx, scriptRoot, outputFileName); + let source: string; + + if (framework === "foundry") { + source = await renderFoundryDeployScript(model); + } else if (framework === "hardhat" && toolbox === "viem") { + source = await renderHardhatViemDeployScript(model); + } else if (framework === "hardhat") { + source = await renderHardhatEthersDeployScript(model); + } else { + throw new Error(`Cannot generate deploy script: unsupported framework ${framework}.`); + } + + await fs.mkdir(path.dirname(model.outputPath), { recursive: true }); + await fs.writeFile(model.outputPath, source, "utf8"); + + ctx.state.generateDeployScript = { + success: true, + result: { + outputPath: model.outputPath, + facets: model.facets.map((facet) => ({ + facetName: facet.facetName, + contractName: facet.contractName, + importPath: facet.importPath, + group: facet.group, + })), + framework, + toolbox: framework === "hardhat" ? toolbox : null, + }, + error: null, + }; + + return ctx; + }, +}; diff --git a/cli/src/modules/deployGeneration/renderers.ts b/cli/src/modules/deployGeneration/renderers.ts new file mode 100644 index 00000000..e054f51f --- /dev/null +++ b/cli/src/modules/deployGeneration/renderers.ts @@ -0,0 +1,127 @@ +import { DeployFacetEntry, DeployGenerationModel } from "./types"; +import { toCamelCase } from "../../utils/strings"; +import { loadTemplate } from "../../utils/codegen"; + +/** + * Renders a Foundry (Solidity) deploy script that deploys a Diamond proxy + * with all facets in base-first, library-second order. + * + * @param model - The deploy generation model with facet entries and output path. + * @returns The complete Solidity deploy script source code. + */ +export async function renderFoundryDeployScript(model: DeployGenerationModel): Promise { + const template = await loadTemplate("deploy", "foundry-deploy.sol"); + + const imports = model.facets + .map((facet) => { + const importPath = facet.origin === "local" + ? `../${facet.importPath}` + : facet.importPath; + return `import {${facet.contractName}} from "${importPath}";`; + }) + .join("\n"); + const baseFacets = model.facets.filter((facet) => facet.group === "base"); + const libraryFacets = model.facets.filter((facet) => facet.group === "library"); + let index = 0; + + const renderDeployLine = (facet: DeployFacetEntry): string => { + const line = ` facets[${index}] = address(new ${facet.contractName}()); + console.log("${facet.contractName}:", facets[${index}]);`; + index += 1; + return line; + }; + + const baseLines = baseFacets.map(renderDeployLine).join("\n"); + const libraryLines = libraryFacets.map(renderDeployLine).join("\n"); + + return template + .replace("{{IMPORTS}}", imports) + .replace("{{FACET_COUNT}}", String(model.facets.length)) + .replace("{{BASE_LINES}}", baseLines) + .replace("{{LIBRARY_LINES}}", libraryLines); +} + +/** + * Renders a single facet deployment line using Hardhat + ethers.js. + * + * @param facet - The facet entry to deploy. + * @returns TypeScript code that deploys the facet and pushes its address. + */ +function renderHardhatEthersFacetDeploy(facet: DeployFacetEntry): string { + const variableName = toCamelCase(facet.contractName) || "facet"; + return ` const ${variableName} = await ethers.deployContract("${facet.contractName}"); + await ${variableName}.waitForDeployment(); + console.log("${facet.contractName}:", await ${variableName}.getAddress()); + facets.push(await ${variableName}.getAddress());`; +} + +/** + * Renders a single facet deployment line using Hardhat + viem. + * + * @param facet - The facet entry to deploy. + * @returns TypeScript code that deploys the facet and pushes its address. + */ +function renderHardhatViemFacetDeploy(facet: DeployFacetEntry): string { + const variableName = toCamelCase(facet.contractName) || "facet"; + return ` const ${variableName} = await viem.deployContract("${facet.contractName}"); + console.log("${facet.contractName}:", ${variableName}.address); + facets.push(${variableName}.address);`; +} + +/** + * Renders base and library facet deploy sections for a Hardhat deploy script + * using the provided per-facet renderer. + * + * @param model - The deploy generation model with facet entries. + * @param renderFacetDeploy - Callback to render a single facet's deploy code. + * @returns An object with `baseLines` and `libraryLines` strings. + */ +function renderHardhatDeploySections( + model: DeployGenerationModel, + renderFacetDeploy: (facet: DeployFacetEntry) => string, +): { baseLines: string; libraryLines: string } { + const baseLines = model.facets + .filter((facet) => facet.group === "base") + .map(renderFacetDeploy) + .join("\n\n"); + const libraryLines = model.facets + .filter((facet) => facet.group === "library") + .map(renderFacetDeploy) + .join("\n\n"); + + return { baseLines, libraryLines }; +} + +/** + * Renders a complete Hardhat + ethers.js deploy script that deploys a Diamond proxy. + * + * @param model - The deploy generation model with facet entries and output path. + * @returns The complete TypeScript deploy script source code. + */ +export async function renderHardhatEthersDeployScript(model: DeployGenerationModel): Promise { + const [template, { baseLines, libraryLines }] = await Promise.all([ + loadTemplate("deploy", "hardhat-ethers-deploy.ts"), + renderHardhatDeploySections(model, renderHardhatEthersFacetDeploy), + ]); + + return template + .replace("{{BASE_LINES}}", baseLines) + .replace("{{LIBRARY_LINES}}", libraryLines); +} + +/** + * Renders a complete Hardhat + viem deploy script that deploys a Diamond proxy. + * + * @param model - The deploy generation model with facet entries and output path. + * @returns The complete TypeScript deploy script source code. + */ +export async function renderHardhatViemDeployScript(model: DeployGenerationModel): Promise { + const [template, { baseLines, libraryLines }] = await Promise.all([ + loadTemplate("deploy", "hardhat-viem-deploy.ts"), + renderHardhatDeploySections(model, renderHardhatViemFacetDeploy), + ]); + + return template + .replace("{{BASE_LINES}}", baseLines) + .replace("{{LIBRARY_LINES}}", libraryLines); +} diff --git a/cli/src/modules/deployGeneration/types.ts b/cli/src/modules/deployGeneration/types.ts new file mode 100644 index 00000000..d13617c3 --- /dev/null +++ b/cli/src/modules/deployGeneration/types.ts @@ -0,0 +1,17 @@ +import { FacetOrigin, SelectedFacetSource } from "../scaffolding/types"; + +export type DeployFacetGroup = "base" | "library"; + +export type DeployFacetEntry = { + facetName: string; + contractName: string; + importPath: string; + source: SelectedFacetSource; + origin: FacetOrigin; + group: DeployFacetGroup; +}; + +export type DeployGenerationModel = { + outputPath: string; + facets: DeployFacetEntry[]; +}; diff --git a/cli/src/modules/diamondGeneration/model.ts b/cli/src/modules/diamondGeneration/model.ts new file mode 100644 index 00000000..bb2a940b --- /dev/null +++ b/cli/src/modules/diamondGeneration/model.ts @@ -0,0 +1,218 @@ +import path from "node:path"; +import { ComposeContext } from "../../context/types"; +import { ConstructorEntry, Erc165Entry } from "../config/types"; +import { getSelectedFacets, targetDirectoryForFacet } from "../scaffolding/module"; +import { BasesCatalog } from "../config/types"; +import { resolveCatalogSelection, EMPTY_BASE } from "../config/module"; +import { DiamondGenerationFile, DiamondGenerationModel, DiamondImport } from "./types"; +import { + contractNameFromSourcePath, + isComposePackagePath, + resolveCatalogSourceForRead, +} from "../../utils/soliditySources"; +import { toRelativeImport } from "../../utils/files"; +import { dedupeBy } from "../../utils/arrays"; + +const DIAMOND_MOD_PATH = "@perfect-abstractions/compose/diamond/DiamondMod.sol"; +const ERC165_MOD_PATH = "@perfect-abstractions/compose/interfaceDetection/ERC165/ERC165Mod.sol"; + +/** + * Resolves the complete Diamond generation model by collecting imports, constructor + * entries, ERC-165 registrations, and file copy operations from all selected facets. + * + * @param ctx - The compose context with project parameters and config. + * @param contractSourceRoot - Directory where generated Solidity files will be written. + * @returns The fully resolved diamond generation model. + * @throws {Error} If base is unknown, pragma is invalid, or facets have conflicts. + */ +export function resolveDiamondGenerationModel( + ctx: ComposeContext, + contractSourceRoot: string, +): DiamondGenerationModel { + const catalog = ctx.config.bases as BasesCatalog; + const selectedBaseKey = String(ctx.param.base ?? ""); + const selectedBase = selectedBaseKey === "none" + ? EMPTY_BASE + : catalog.features[selectedBaseKey]; + const projectRoot = String(ctx.param.projectRoot ?? ""); + const solidityPragma = catalog.globals.diamond?.pragma; + + if (!selectedBase) { + throw new Error(`Cannot generate Diamond.sol: unknown base "${selectedBaseKey}".`); + } + if (!projectRoot || !contractSourceRoot) { + throw new Error("Cannot generate Diamond.sol: project root is not defined."); + } + if ( + typeof solidityPragma !== "string" || + solidityPragma.trim().length === 0 || + /[;\r\n]/.test(solidityPragma) + ) { + throw new Error("Cannot generate Diamond.sol: diamond pragma is missing or invalid."); + } + + const selectedFacets = getSelectedFacets(ctx); + const selection = resolveCatalogSelection( + catalog, + selectedBaseKey, + (ctx.param.libraries as string[] | undefined) ?? [], + (ctx.param.extensions as string[] | undefined) ?? [], + (ctx.param.access as string[] | undefined) ?? [], + (ctx.param.accessExtensions as string[] | undefined) ?? [], + ); + const erc165Selected = selectedFacets.some((facet) => facet.name === "ERC165Facet"); + const imports: DiamondImport[] = []; + const files: DiamondGenerationFile[] = []; + const constructorEntries: ConstructorEntry[] = []; + const erc165Registrations: Erc165Entry[] = []; + + addDiamondImport(imports, { + alias: "DiamondMod", + path: DIAMOND_MOD_PATH, + style: "alias", + }); + + for (const facet of selectedFacets) { + const entry = facet.entry; + const entryConstructorEntries = Array.isArray(entry.constructor) ? entry.constructor : []; + + for (const constructorEntry of entryConstructorEntries) { + if ( + !constructorEntry || + typeof constructorEntry !== "object" || + typeof constructorEntry.code !== "string" || + constructorEntry.code.trim().length === 0 + ) { + throw new Error(`Cannot generate Diamond.sol: ${facet.name} has an invalid constructor entry.`); + } + if ( + constructorEntry.comments !== undefined && + (!Array.isArray(constructorEntry.comments) || + constructorEntry.comments.some((comment) => typeof comment !== "string" || comment.trim().length === 0)) + ) { + throw new Error(`Cannot generate Diamond.sol: ${facet.name} has invalid constructor comments.`); + } + if (/\{\{[^}]+\}\}/.test(constructorEntry.code)) { + throw new Error(`Cannot generate Diamond.sol: ${facet.name} has an unresolved constructor value.`); + } + } + + if (entry.mod) { + const alias = contractNameFromSourcePath(entry.mod); + const target = path.join(targetDirectoryForFacet(contractSourceRoot, facet), path.basename(entry.mod)); + if (!isComposePackagePath(entry.mod)) { + addGenerationFile(files, resolveCatalogSourceForRead(entry.mod), target); + } + if (entryConstructorEntries.length > 0) { + addDiamondImport(imports, { + alias, + path: isComposePackagePath(entry.mod) ? entry.mod : toRelativeImport(path.relative(contractSourceRoot, target)), + style: "alias", + }); + } + } + + constructorEntries.push(...entryConstructorEntries); + } + + if (erc165Selected) { + addDiamondImport(imports, { + alias: "ERC165Mod", + path: ERC165_MOD_PATH, + style: "alias", + }); + + addErc165Metadata(selectedBase.erc165, contractSourceRoot, imports, files, erc165Registrations); + for (const accessBase of selection.selectedAccessBases) { + addErc165Metadata( + accessBase.erc165, + contractSourceRoot, + imports, + files, + erc165Registrations, + ); + } + for (const facet of selectedFacets) { + addErc165Metadata(facet.entry.erc165, contractSourceRoot, imports, files, erc165Registrations); + } + } + + return { + contractName: "Diamond", + solidityPragma: solidityPragma.trim(), + outputPath: path.join(contractSourceRoot, "Diamond.sol"), + imports, + constructorEntries: dedupeBy(constructorEntries, (entry) => entry.code), + erc165Registrations: dedupeBy(erc165Registrations, (entry) => entry.id), + files, + }; +} + +/** + * Adds ERC-165 metadata to the generation model, including the import statement, + * file copy entry, and interface registration. + * + * @param metadata - The ERC-165 entry to add, or undefined to skip. + * @param contractSourceRoot - Directory where interface files will be written. + * @param imports - Mutable array of diamond imports to append to. + * @param files - Mutable array of file generation entries to append to. + * @param registrations - Mutable array of ERC-165 registrations to append to. + * @throws {Error} If metadata is missing path or id. + */ +function addErc165Metadata( + metadata: Erc165Entry | undefined, + contractSourceRoot: string, + imports: DiamondImport[], + files: DiamondGenerationFile[], + registrations: Erc165Entry[], +): void { + if (!metadata) return; + if (!metadata.path || !metadata.id) { + throw new Error("Invalid ERC-165 metadata: both path and id are required."); + } + + const alias = contractNameFromSourcePath(metadata.path); + const target = path.join(contractSourceRoot, "interfaces", path.basename(metadata.path)); + if (!isComposePackagePath(metadata.path)) { + addGenerationFile(files, resolveCatalogSourceForRead(metadata.path), target); + } + addDiamondImport(imports, { + alias, + path: isComposePackagePath(metadata.path) ? metadata.path : toRelativeImport(path.relative(contractSourceRoot, target)), + style: "named", + }); + registrations.push(metadata); +} + +/** + * Adds a diamond import to the list, ensuring no alias conflicts exist. + * + * @param imports - Mutable array of existing imports. + * @param candidate - The import to add. + * @throws {Error} If the alias already maps to a different path. + */ +function addDiamondImport(imports: DiamondImport[], candidate: DiamondImport): void { + const aliasMatch = imports.find((entry) => entry.alias === candidate.alias); + if (aliasMatch && aliasMatch.path !== candidate.path) { + throw new Error( + `Cannot generate Diamond.sol: import alias ${candidate.alias} maps to both ${aliasMatch.path} and ${candidate.path}.`, + ); + } + if (!aliasMatch) imports.push(candidate); +} + +/** + * Adds a file generation entry, ensuring no target path conflicts exist. + * + * @param files - Mutable array of file generation entries. + * @param source - Source file path to copy from. + * @param target - Target file path to copy to. + * @throws {Error} If multiple sources map to the same target. + */ +function addGenerationFile(files: DiamondGenerationFile[], source: string, target: string): void { + const targetMatch = files.find((entry) => entry.target === target); + if (targetMatch && targetMatch.source !== source) { + throw new Error(`Cannot generate Diamond.sol: multiple sources map to ${target}.`); + } + if (!targetMatch) files.push({ source, target }); +} diff --git a/cli/src/modules/diamondGeneration/module.ts b/cli/src/modules/diamondGeneration/module.ts new file mode 100644 index 00000000..d18bf500 --- /dev/null +++ b/cli/src/modules/diamondGeneration/module.ts @@ -0,0 +1,58 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../../context/types"; +import { copyFileIfMissing, findMissingFiles } from "../../utils/files"; +import { renderDiamondContract } from "./renderer"; +import { resolveDiamondGenerationModel } from "./model"; +import { DiamondGenerationFile, DiamondImport } from "./types"; + +/** + * Module responsible for generating the Diamond.sol proxy contract and + * copying supporting files to the project source directory. + */ +export const DiamondGenerationModule = { + /** + * Generates the Diamond contract, copies supporting files, and updates + * the compose context state with the results. + * + * @param ctx - The compose context with project parameters and state. + * @param contractSourceRoot - Directory where Solidity source files live. + * @returns The updated compose context with generation results. + * @throws {Error} If source files are missing or file operations fail. + */ + async generateDiamondContract( + ctx: ComposeContext, + contractSourceRoot: string, + ): Promise { + const model = resolveDiamondGenerationModel(ctx, contractSourceRoot); + const missingFiles = await findMissingFiles( + model.files.map((file: DiamondGenerationFile) => file.source), + ); + + if (missingFiles.length > 0) { + throw new Error(`Cannot generate Diamond.sol: source files not found:\n${missingFiles.join("\n")}`); + } + + for (const file of model.files) { + await copyFileIfMissing(file.source, file.target); + } + + const source = await renderDiamondContract(model); + await fs.mkdir(path.dirname(model.outputPath), { recursive: true }); + await fs.writeFile(model.outputPath, source, "utf8"); + + ctx.state.generateDiamondContract = { + success: true, + result: { + outputPath: model.outputPath, + copiedFiles: model.files.map((file: DiamondGenerationFile) => file.target), + imports: model.imports.map((entry: DiamondImport) => entry.path), + constructorEntries: model.constructorEntries, + erc165Registrations: model.erc165Registrations.map((entry) => entry.id), + }, + error: null, + }; + + return ctx; + }, +}; diff --git a/cli/src/modules/diamondGeneration/renderer.ts b/cli/src/modules/diamondGeneration/renderer.ts new file mode 100644 index 00000000..067d1306 --- /dev/null +++ b/cli/src/modules/diamondGeneration/renderer.ts @@ -0,0 +1,73 @@ +import { ConstructorEntry, Erc165Entry } from "../config/types"; +import { DiamondGenerationModel, DiamondImport } from "./types"; +import { loadTemplate } from "../../utils/codegen"; + +/** + * Renders the complete Diamond.sol contract by filling a template with imports, + * constructor blocks, and ERC-165 registrations from the generation model. + * + * @param model - The diamond generation model with all data needed for rendering. + * @returns The complete Solidity source code for Diamond.sol. + */ +export async function renderDiamondContract(model: DiamondGenerationModel): Promise { + const template = await loadTemplate("diamond", "diamond.sol"); + + const imports = model.imports.map(renderDiamondImport).join("\n"); + const constructorBlocks = [ + " DiamondMod.addFacets(_facets);", + ...model.constructorEntries.map(renderConstructorEntry), + ...model.erc165Registrations.map(renderErc165Registration), + ].join("\n\n"); + + return template + .replace("{{SOLIDITY_PRAGMA}}", model.solidityPragma) + .replace("{{IMPORTS}}", imports) + .replace("{{CONTRACT_NAME}}", model.contractName) + .replace("{{CONSTRUCTOR_BLOCKS}}", constructorBlocks); +} + +/** + * Renders a single Solidity import statement in named or alias style. + * + * @param entry - The diamond import entry to render. + * @returns The formatted import statement string. + */ +function renderDiamondImport(entry: DiamondImport): string { + if (entry.style === "named") return `import {${entry.alias}} from "${entry.path}";`; + return `import "${entry.path}" as ${entry.alias};`; +} + +/** + * Renders a constructor entry with optional preceding comment lines. + * + * @param entry - The constructor entry containing code and optional comments. + * @returns The formatted constructor code block. + */ +function renderConstructorEntry(entry: ConstructorEntry): string { + return renderCommentedCode(entry.comments, entry.code); +} + +/** + * Renders an ERC-165 interface registration call with optional comments. + * + * @param entry - The ERC-165 entry containing the interface ID and comments. + * @returns The formatted registration code block. + */ +function renderErc165Registration(entry: Erc165Entry): string { + return renderCommentedCode(entry.comments, `ERC165Mod.registerInterface(${entry.id});`); +} + +/** + * Renders a code line with optional comment lines above it, each indented + * with 8 spaces to align with the Diamond contract body. + * + * @param comments - Optional array of comment strings (may contain newlines). + * @param code - The code line to render. + * @returns The formatted block with comments and code. + */ +function renderCommentedCode(comments: string[] | undefined, code: string): string { + return [ + ...(comments ?? []).flatMap((comment) => comment.split(/\r?\n/).map((line) => ` // ${line}`)), + ` ${code}`, + ].join("\n"); +} diff --git a/cli/src/modules/diamondGeneration/types.ts b/cli/src/modules/diamondGeneration/types.ts new file mode 100644 index 00000000..8ba6f475 --- /dev/null +++ b/cli/src/modules/diamondGeneration/types.ts @@ -0,0 +1,22 @@ +import { ConstructorEntry, Erc165Entry } from "../config/types"; + +export type DiamondImport = { + alias: string; + path: string; + style: "alias" | "named"; +}; + +export type DiamondGenerationFile = { + source: string; + target: string; +}; + +export type DiamondGenerationModel = { + contractName: string; + solidityPragma: string; + outputPath: string; + imports: DiamondImport[]; + constructorEntries: ConstructorEntry[]; + erc165Registrations: Erc165Entry[]; + files: DiamondGenerationFile[]; +}; diff --git a/cli/src/modules/info/loader.ts b/cli/src/modules/info/loader.ts new file mode 100644 index 00000000..14fc2a22 --- /dev/null +++ b/cli/src/modules/info/loader.ts @@ -0,0 +1,104 @@ +import fs from "node:fs/promises"; +import { ComposeContext } from "../../context/types"; +import { DiamondInfo, FacetInfo } from "./types"; +import { findFileAncestor } from "../../utils/files"; + +/** + * Reads and parses compose.json, storing the result in ctx.state.infoLoader. + * + * @param ctx - The compose context with project root parameter. + * @returns The updated context with loader state. + */ +export async function loadComposeJson(ctx: ComposeContext): Promise { + const startDir = String(ctx.param.projectRoot ?? process.cwd()); + const composeJsonPath = await findFileAncestor(startDir, "compose.json"); + + if (!composeJsonPath) { + ctx.state.infoLoader = { + success: false, + result: null, + error: { + code: "COMPOSE_JSON_NOT_FOUND", + message: "compose.json not found. Run 'compose init' first or navigate to a Compose project directory.", + nativeError: null, + }, + }; + return ctx; + } + + const content = await fs.readFile(composeJsonPath, "utf8"); + const composeJson = JSON.parse(content); + + ctx.config.composeJson = composeJson; + ctx.state.infoLoader = { + success: true, + result: { + composeJsonPath, + composeJson, + }, + error: null, + }; + + return ctx; +} + +/** + * Parses the raw compose.json into structured ComposeProjectInfo. + * + * @param ctx - The compose context with loaded compose.json state. + * @returns The updated context with parsed project info. + */ +export function parseProjectInfo(ctx: ComposeContext): ComposeContext { + const loaderState = ctx.state.infoLoader as { success: boolean; result: { composeJson: Record } | null }; + if (!loaderState?.success || !loaderState?.result) { + return ctx; + } + + const composeJson = loaderState.result.composeJson; + const project = String(composeJson.project ?? "unknown"); + const composeVersion = String(composeJson.compose ?? "unknown"); + const framework = String(composeJson.framework ?? "unknown"); + + const diamondsRaw = composeJson.diamonds as Record }> | undefined; + const diamonds: DiamondInfo[] = []; + const warnings: string[] = []; + + if (!diamondsRaw) { + warnings.push("No diamonds defined in compose.json"); + } else { + for (const [diamondName, diamondDef] of Object.entries(diamondsRaw)) { + const facets: FacetInfo[] = []; + + for (const [facetName, facetDef] of Object.entries(diamondDef.facets)) { + facets.push({ + name: facetName, + source: facetDef.source as FacetInfo["source"], + contract: facetDef.contract, + package: facetDef.package, + selectors: [], + storageSlots: [], + }); + } + + diamonds.push({ + name: diamondName, + contract: diamondDef.contract, + facets, + }); + } + } + + ctx.state.infoProject = { + success: true, + result: { + project, + composeVersion, + framework, + diamonds, + warnings, + }, + error: null, + }; + + return ctx; +} diff --git a/cli/src/modules/info/module.ts b/cli/src/modules/info/module.ts new file mode 100644 index 00000000..cd872e13 --- /dev/null +++ b/cli/src/modules/info/module.ts @@ -0,0 +1,33 @@ +import { ComposeContext } from "../../context/types"; +import { loadComposeJson, parseProjectInfo } from "./loader"; +import { scanFacets } from "./scanner"; +import { showInfo } from "./output"; + +/** + * Info Module. + * + * Loads compose.json, scans facets for selectors and storage layouts, + * and displays a summary of the local project. + */ +export const InfoModule = { + /** + * Executes the full info command flow + * + * @param ctx - The compose context with project root parameter. + * @returns The updated context with info state populated. + */ + async displayProjectInfo(ctx: ComposeContext): Promise { + ctx = await loadComposeJson(ctx); + + const loaderState = ctx.state.infoLoader as { success: boolean; error: { message: string } | null } | undefined; + if (loaderState && !loaderState.success) { + throw new Error(loaderState.error?.message ?? "Failed to load compose.json"); + } + + ctx = parseProjectInfo(ctx); + ctx = await scanFacets(ctx); + showInfo(ctx); + + return ctx; + }, +}; diff --git a/cli/src/modules/info/output.ts b/cli/src/modules/info/output.ts new file mode 100644 index 00000000..7f8f6d57 --- /dev/null +++ b/cli/src/modules/info/output.ts @@ -0,0 +1,146 @@ +import { ComposeContext } from "../../context/types"; +import { cyan, dim, green, yellow } from "../../utils/terminal"; +import { ComposeProjectInfo, DiamondInfo, FacetInfo, StorageSlotInfo } from "./types"; + +/** + * Formats and displays the project info summary to the console. + * + * @param ctx - The compose context with scanned project info. + */ +export function showInfo(ctx: ComposeContext): void { + const projectState = ctx.state.infoProject as { success: boolean; result: ComposeProjectInfo | null } | undefined; + if (!projectState?.success || !projectState?.result) { + console.error("No project info available."); + return; + } + + const info = projectState.result; + + // Header + console.log(cyan(`Project: ${info.project}`)); + console.log(dim(`Framework: ${info.framework}`)); + console.log(""); + + if (info.diamonds.length === 0) { + console.log(yellow(" No diamonds defined in compose.json")); + return; + } + + // Diamonds + for (const diamond of info.diamonds) { + printDiamond(diamond); + } + + // Warnings + if (info.warnings.length > 0) { + console.log(yellow("\nWarnings:")); + for (const warning of info.warnings) { + console.log(yellow(` ${warning}`)); + } + } + + console.log(""); +} + +/** + * Prints a single diamond's summary to the console. + * + * @param diamond - The diamond info to print. + */ +function printDiamond(diamond: DiamondInfo): void { + console.log(cyan(`Diamond: ${diamond.name}`)); + console.log(dim(` Contract: ${diamond.contract}`)); + console.log(""); + + if (diamond.facets.length === 0) { + console.log(dim(" No facets defined")); + console.log(""); + return; + } + + console.log(` Facets (${diamond.facets.length}):`); + console.log(""); + + for (const facet of diamond.facets) { + printFacet(facet); + } +} + +/** + * Prints a single facet's summary to the console. + * + * @param facet - The facet info to print. + */ +function printFacet(facet: FacetInfo): void { + console.log(green(` ${facet.name}`)); + printSource(facet); + printSelectors(facet); + printStorageSlots(facet); + console.log(""); +} + +/** + * Prints the facet source type and path to the console. + * + * @param facet - The facet info to print source for. + */ +function printSource(facet: FacetInfo): void { + switch (facet.source) { + case "local": + console.log(dim(` Source: local (${facet.contract})`)); + break; + case "package": + console.log(dim(` Source: package (${facet.package ?? "unknown"})`)); + break; + case "registry": + console.log(dim(` Source: registry`)); + break; + default: + console.log(dim(` Source: ${facet.source}`)); + } +} + +/** + * Prints the facet's exported selectors to the console. + * + * @param facet - The facet info to print selectors for. + */ +function printSelectors(facet: FacetInfo): void { + if (facet.selectors.length === 0) { + console.log(dim(" Selectors: (none)")); + return; + } + + console.log(" Selectors:"); + for (const selector of facet.selectors) { + console.log(` ${selector}`); + } +} + +/** + * Prints the facet's storage slot annotations to the console. + * + * @param facet - The facet info to print storage slots for. + */ +function printStorageSlots(facet: FacetInfo): void { + if (facet.storageSlots.length === 0) { + return; + } + + console.log(" Storage:"); + for (const slot of facet.storageSlots) { + printStorageSlot(slot); + } +} + +/** + * Prints a single storage slot annotation to the console. + * + * @param slot - The storage slot info to print. + */ +function printStorageSlot(slot: StorageSlotInfo): void { + const structLabel = slot.structName ? ` (${slot.structName})` : ""; + const layoutStr = slot.layout.length > 0 ? ` [${slot.layout.join(", ")}]` : ""; + + console.log(` ${slot.slot}${structLabel}${layoutStr}`); +} diff --git a/cli/src/modules/info/scanner.ts b/cli/src/modules/info/scanner.ts new file mode 100644 index 00000000..6dd0d3bd --- /dev/null +++ b/cli/src/modules/info/scanner.ts @@ -0,0 +1,204 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../../context/types"; +import { + extractSolidityContractBody, + parseExportedSelectorSignatures, + parseSolidityFunctions, +} from "../../utils/solidityText"; +import { parseStorageLayouts } from "../scaffolding/module"; +import { ComposeProjectInfo, DiamondInfo, FacetInfo } from "./types"; + +/** + * Resolves a local facet contract path to an absolute file path, + * relative to the compose.json directory. + * + * @param contract - The contract reference from compose.json (may contain ":" suffix). + * @param composeJsonDir - Directory containing compose.json. + * @returns The resolved absolute file path. + */ +function resolveLocalFacetPath( + contract: string, + composeJsonDir: string, +): string { + const contractPath = contract.split(":")[0]; + return path.resolve(composeJsonDir, contractPath); +} + +/** + * Searches for a package facet's .sol file in the installed package directories. + * Checks node_modules and Foundry lib directories. + * + * @param facetName - Name of the facet contract file (without extension). + * @param packageName - The npm or package name to search within. + * @param projectRoot - The project root directory. + * @returns The resolved absolute path, or null if not found. + */ +async function resolvePackageFacetPath( + facetName: string, + packageName: string, + projectRoot: string, +): Promise { + const candidates = [ + path.join(projectRoot, "node_modules", packageName), + path.join(projectRoot, "lib", "Compose", "src"), + ]; + + for (const candidate of candidates) { + try { + const entries = await fs.readdir(candidate, { recursive: true, withFileTypes: true }); + for (const entry of entries) { + if (entry.isFile() && entry.name === `${facetName}.sol`) { + return path.join(entry.parentPath ?? entry.path, entry.name); + } + } + } catch { + // Directory doesn't exist, continue + } + } + + return null; +} + +/** + * Scans all facets in all diamonds to extract selectors and storage layouts. + * Updates the projectInfo in ctx.state.infoProject with the scanned data. + * + * @param ctx - The compose context with parsed project info. + * @returns The updated context with scanned facet data. + */ +export async function scanFacets(ctx: ComposeContext): Promise { + const projectState = ctx.state.infoProject as { success: boolean; result: ComposeProjectInfo | null } | undefined; + if (!projectState?.success || !projectState?.result) { + return ctx; + } + + const loaderState = ctx.state.infoLoader as { result: { composeJsonPath: string } | null } | undefined; + const composeJsonPath = loaderState?.result?.composeJsonPath; + if (!composeJsonPath) { + return ctx; + } + + const composeJsonDir = path.dirname(composeJsonPath); + const projectInfo = projectState.result; + const warnings: string[] = [...projectInfo.warnings]; + + for (const diamond of projectInfo.diamonds) { + await scanDiamond(diamond, composeJsonDir, warnings); + } + + projectInfo.warnings = warnings; + + ctx.state.infoProject = { + success: true, + result: projectInfo, + error: null, + }; + + return ctx; +} + +/** + * Scans a single diamond's facets for selectors and storage layouts. + * + * @param diamond - The diamond to scan (mutated in place). + * @param composeJsonDir - Directory containing compose.json for path resolution. + * @param warnings - Mutable array to append warning messages to. + */ +async function scanDiamond( + diamond: DiamondInfo, + composeJsonDir: string, + warnings: string[], +): Promise { + for (const facet of diamond.facets) { + await scanFacet(facet, composeJsonDir, warnings); + } +} + +/** + * Scans a single facet for selectors and storage layouts by reading its source file. + * + * @param facet - The facet to scan (mutated in place). + * @param composeJsonDir - Directory containing compose.json for path resolution. + * @param warnings - Mutable array to append warning messages to. + */ +async function scanFacet( + facet: FacetInfo, + composeJsonDir: string, + warnings: string[], +): Promise { + if (facet.source === "package") { + if (!facet.package) { + warnings.push(`Package facet ${facet.name}: missing "package" field in compose.json`); + return; + } + + const resolvedPath = await resolvePackageFacetPath(facet.name, facet.package, composeJsonDir); + if (!resolvedPath) { + warnings.push(`Package facet ${facet.name}: source not found in ${facet.package}`); + return; + } + + try { + const source = await fs.readFile(resolvedPath, "utf8"); + extractFacetInfo(facet, source, warnings); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + warnings.push(`Package facet ${facet.name}: cannot read source - ${message}`); + } + return; + } + + // Local facets: resolve relative to compose.json directory + try { + const resolvedPath = resolveLocalFacetPath(facet.contract, composeJsonDir); + const source = await fs.readFile(resolvedPath, "utf8"); + extractFacetInfo(facet, source, warnings); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + warnings.push(`Facet ${facet.name}: cannot read source - ${message}`); + } +} + +/** + * Extracts selectors and storage layouts from facet Solidity source code. + * + * @param facet - The facet to populate (mutated in place). + * @param source - The Solidity source code string. + * @param warnings - Mutable array to append warning messages to. + */ +function extractFacetInfo( + facet: FacetInfo, + source: string, + warnings: string[], +): void { + const contractBody = extractSolidityContractBody(source, facet.name); + if (!contractBody) { + warnings.push(`Facet ${facet.name}: contract ${facet.name} not found in source`); + return; + } + + // Extract functions and exported selectors + const functions = parseSolidityFunctions(contractBody); + const exportedSignatures = parseExportedSelectorSignatures(contractBody, functions); + facet.selectors = exportedSignatures; + + if (exportedSignatures.length === 0) { + warnings.push(`Facet ${facet.name}: no exported selectors found`); + } + + // Extract storage layouts + const storageScan = parseStorageLayouts(source); + facet.storageSlots = storageScan.layouts.map((layout) => ({ + slot: layout.slot, + layout: layout.layout, + source: layout.source, + structName: layout.structName, + })); + + if (storageScan.warnings.length > 0) { + for (const warning of storageScan.warnings) { + warnings.push(`Facet ${facet.name}: ${warning}`); + } + } +} diff --git a/cli/src/modules/info/types.ts b/cli/src/modules/info/types.ts new file mode 100644 index 00000000..8222633f --- /dev/null +++ b/cli/src/modules/info/types.ts @@ -0,0 +1,35 @@ +export type FacetInfo = { + name: string; + source: "local" | "package" | "registry"; + contract: string; + package?: string; + selectors: string[]; + storageSlots: StorageSlotInfo[]; +}; + +export type StorageSlotInfo = { + slot: string; + layout: string[]; + source: "erc8042" | "slot-assignment"; + structName: string | null; +}; + +export type DiamondInfo = { + name: string; + contract: string; + facets: FacetInfo[]; +}; + +export type ComposeProjectInfo = { + project: string; + composeVersion: string; + framework: string; + diamonds: DiamondInfo[]; + warnings: string[]; +}; + +export type InfoState = { + composeJsonPath: string; + composeJson: Record; + projectInfo: ComposeProjectInfo; +}; diff --git a/cli/src/modules/init/flags.ts b/cli/src/modules/init/flags.ts new file mode 100644 index 00000000..b2a3946c --- /dev/null +++ b/cli/src/modules/init/flags.ts @@ -0,0 +1,33 @@ +import { uniqueStrings, splitCommaSeparated } from "../../utils/strings"; +import { AccessFlagSelection } from "./types"; + +/** + * Resolves grouped access flags from raw CLI parameters into a structured selection. + * Ensures at most one ownership base is selected. + * + * @param param - Raw CLI parameter record containing access-related flags. + * @returns The resolved access flag selection with deduplicated values. + * @throws {Error} If more than one ownership base is provided. + */ +export function resolveAccessFlags(param: Record): AccessFlagSelection { + const ownership = splitCommaSeparated(param.ownership); + if (ownership.length > 1) { + throw new Error("--ownership accepts only one ownership base."); + } + + return { + selectedOwnership: ownership, + selectedRoleAccess: splitCommaSeparated(param.accessControl), + selectedOwnershipExtensions: splitCommaSeparated(param.ownershipExtensions), + selectedRoleAccessExtensions: splitCommaSeparated(param.accessControlExtensions), + selectedAccess: uniqueStrings([ + ...ownership, + ...splitCommaSeparated(param.accessControl), + ]), + selectedAccessExtensions: uniqueStrings([ + ...splitCommaSeparated(param.ownershipExtensions), + ...splitCommaSeparated(param.accessControlExtensions), + ]), + }; +} + diff --git a/cli/src/modules/init/framework-deps.ts b/cli/src/modules/init/framework-deps.ts new file mode 100644 index 00000000..51e515f1 --- /dev/null +++ b/cli/src/modules/init/framework-deps.ts @@ -0,0 +1,43 @@ +import { FrameworkDependencies } from "./types"; + +/** + * Returns the framework-specific dependencies needed for a Compose project. + * Foundry uses git submodules; Hardhat uses npm packages. + * + * @param framework - The target framework ("foundry" or "hardhat"). + * @param toolbox - The Hardhat toolbox ("ethers" or "viem"). Ignored for Foundry. + * @returns The dependency list and package type label. + */ +export function getFrameworkDependencies( + framework: string, + toolbox?: string, +): FrameworkDependencies { + if (framework === "foundry") { + return { + deps: [ + { name: "forge-std", version: "(git submodule)" }, + { name: "Perfect-Abstractions/Compose", version: "(git submodule)" }, + ], + packageType: "forge packages", + }; + } + + const devDeps: Record = + toolbox === "viem" + ? { + hardhat: "^3.8.0", + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.0", + } + : { + hardhat: "^3.8.0", + "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.0", + }; + + return { + deps: [ + { name: "@perfect-abstractions/compose", version: "latest" }, + ...Object.entries(devDeps).map(([name, version]) => ({ name, version })), + ], + packageType: "npm packages", + }; +} diff --git a/cli/src/modules/init/module.ts b/cli/src/modules/init/module.ts new file mode 100644 index 00000000..24dcb8aa --- /dev/null +++ b/cli/src/modules/init/module.ts @@ -0,0 +1,297 @@ +import { ComposeContext } from "../../context/types"; +import { BasesCatalog } from "../config/types"; +import { + EMPTY_BASE, + getAccessBases, + getAvailableLibraryFacets, + resolveCatalogSelection, + validateGroupedAccessFlags, +} from "../config/module"; +import { + checkboxTheme, + getOwnershipChoices, + getOwnershipExtensionChoices, + getRoleAccessChoices, + getRoleAccessExtensionChoices, + loadPrompts, + selectTheme, + toFacetChoices, +} from "./prompts"; +import { getFrameworkDependencies } from "./framework-deps"; +import { resolveAccessFlags } from "./flags"; +import { splitCommaSeparated } from "../../utils/strings"; +import { TerminalOutputModule } from "../terminalOutput/module"; + +/** + * Handles interactive and non-interactive init input collection. + * + * Validates user selections against the loaded bases catalog, resolves + * framework, base, library, extension, access, and example choices, and stores + * the assembled configuration on the context. + */ +export const InitModule = { + /** + * Runs the init flow non-interactively from CLI flags. + * + * Validates the framework (`foundry` or `hardhat`), base key, library + * extensions, access layers, and example selections against the catalog. Defaults the + * Hardhat toolbox to `ethers` if not specified. Throws on any invalid + * selection. + * + * @param ctx - The compose context with CLI flags and the loaded bases catalog. + * @returns The context with init options stored in `ctx.state.entry`. + */ + async runInitNonInteractive(ctx: ComposeContext): Promise { + const catalog = ctx.config.bases as BasesCatalog; + + const framework = String(ctx.param.framework ?? "foundry").toLowerCase(); + if (framework !== "foundry" && framework !== "hardhat") { + throw new Error(`Unsupported framework: ${framework}. Must be "foundry" or "hardhat".`); + } + + if (framework === "hardhat" && !ctx.param.toolbox) { + ctx.param.toolbox = "ethers"; + } + + const baseKey = ctx.param.base ? String(ctx.param.base) : ""; + if (!baseKey) { + throw new Error('Missing required flag: --base'); + } + if (baseKey !== "none" && !catalog.features[baseKey]) { + throw new Error(`Unknown base: ${baseKey}. Available: ${Object.keys(catalog.features).join(", ")}`); + } + + const selectedLibraries = splitCommaSeparated(ctx.param.libraries); + const selectedExtensions = splitCommaSeparated(ctx.param.extensions); + + const { + selectedOwnership, + selectedRoleAccess, + selectedOwnershipExtensions, + selectedRoleAccessExtensions, + selectedAccess, + selectedAccessExtensions, + } = resolveAccessFlags(ctx.param); + + validateGroupedAccessFlags( + catalog, + baseKey, + selectedOwnership, + selectedRoleAccess, + selectedOwnershipExtensions, + selectedRoleAccessExtensions, + ); + + const selection = resolveCatalogSelection( + catalog, + baseKey, + selectedLibraries, + selectedExtensions, + selectedAccess, + selectedAccessExtensions, + ); + + ctx.param.projectName = ctx.param.projectName ?? "my-diamond"; + ctx.param.framework = framework; + ctx.param.base = baseKey; + ctx.param.libraries = selectedLibraries; + ctx.param.extensions = selectedExtensions; + ctx.param.access = selectedAccess; + ctx.param.accessExtensions = selectedAccessExtensions; + + ctx.config.bases = catalog; + ctx.state.entry = { + success: true, + result: { + framework, + selectedBaseKey: baseKey, + selectedBaseLabel: selection.selectedBase.label, + selectedLibraries, + selectedAccess, + selectedExtensions: selection.selectedExtensions, + selectedAccessExtensions: selection.selectedAccessExtensions, + requiredFacets: Object.keys(selection.requiredFacets), + availableLibraryFacets: Object.keys(selection.availableGlobalLibraryFacets), + }, + error: null, + }; + + return ctx; + }, + + /** + * Runs the init flow interactively using `@inquirer/prompts`. + * + * Prompts the user for project name, framework (Foundry/Hardhat), toolbox + * (for Hardhat), base, library facets, extension facets, access layers, + * access extension facets, and local example + * facets via select and checkbox prompts. Each selection is validated against + * the loaded bases catalog. + * + * @param ctx - The compose context with the loaded bases catalog. + * @returns The context with user selections stored in `ctx.state.entry`. + */ + async runInitInteractive(ctx: ComposeContext): Promise { + const { input, checkbox, select } = await loadPrompts(); + const catalog = ctx.config.bases as BasesCatalog; + + if (!ctx.param.projectName) { + const projectName = await input({ + message: "Enter project name:", + default: "my-diamond", + }); + ctx.param.projectName = projectName; + } + + const featureChoices = [ + { name: "Blank project", value: "none" }, + ...Object.entries(catalog.features) + .filter(([, definition]) => definition.access !== true && definition.visible !== false) + .map(([key, definition]) => ({ + name: definition.label, + value: key, + })), + ]; + + const framework = await select({ + message: "Select project framework:", + choices: [ + { name: "Foundry", value: "foundry" }, + { name: "Hardhat", value: "hardhat" }, + ] as const, + default: "foundry", + theme: selectTheme, + }); + + if (framework === "hardhat") { + const toolbox = await select({ + message: "Select Hardhat toolbox:", + choices: [ + { name: "Ethers (hardhat-toolbox-mocha-ethers)", value: "ethers" }, + { name: "Viem (hardhat-toolbox-viem)", value: "viem" }, + ], + default: "ethers", + theme: selectTheme, + }); + ctx.param.toolbox = toolbox; + } + + const selectedBaseKey = await select({ + message: "Select base:", + choices: featureChoices, + theme: selectTheme, + }); + + const selectedBase = selectedBaseKey === "none" + ? EMPTY_BASE + : catalog.features[selectedBaseKey]; + + const availableExtensions = selectedBase.optional ?? {}; + const extensionChoices = toFacetChoices(Object.keys(availableExtensions)); + + const selectedExtensions = extensionChoices.length > 0 + ? await checkbox({ + message: "Select extension facets:", + choices: extensionChoices, + theme: checkboxTheme, + }) + : []; + + const availableLibraryFacets = getAvailableLibraryFacets(catalog, selectedBase); + const libraryChoices = toFacetChoices(Object.keys(availableLibraryFacets)); + + const selectedLibraries = await checkbox({ + message: "Select Compose library facets:", + choices: libraryChoices, + theme: checkboxTheme, + }); + + const accessBases = getAccessBases(catalog, selectedBaseKey); + const selectedOwnership = selectedBase.accessType === "ownership" + ? undefined + : await select({ + message: "Select ownership:", + choices: getOwnershipChoices(accessBases), + theme: selectTheme, + }); + + const ownershipExtensionChoices = getOwnershipExtensionChoices(accessBases, selectedOwnership); + const selectedOwnershipExtensions = ownershipExtensionChoices.length > 0 + ? await checkbox({ + message: "Select ownership extension facets:", + choices: ownershipExtensionChoices, + theme: checkboxTheme, + }) + : []; + + const accessChoices = getRoleAccessChoices(accessBases); + + const selectedAccessControl = await select({ + message: "Select access control:", + choices: accessChoices, + theme: selectTheme, + }); + const selectedRoleAccess = selectedAccessControl ? [selectedAccessControl] : []; + const selectedAccess = [ + ...(selectedOwnership ? [selectedOwnership] : []), + ...selectedRoleAccess, + ]; + + const accessExtensionChoices = getRoleAccessExtensionChoices(accessBases, selectedAccessControl); + + const selectedRoleAccessExtensions = accessExtensionChoices.length > 0 + ? await checkbox({ + message: "Select access control extension facets:", + choices: accessExtensionChoices, + theme: checkboxTheme, + }) + : []; + const selectedAccessExtensions = [ + ...selectedOwnershipExtensions, + ...selectedRoleAccessExtensions, + ]; + + const { deps, packageType } = getFrameworkDependencies(framework, String(ctx.param.toolbox)); + TerminalOutputModule.showDependencies(deps, packageType); + const installDeps = await (await loadPrompts()).confirm({ + message: "Install project dependencies?", + default: true, + }); + ctx.param.installDeps = installDeps; + + const selection = resolveCatalogSelection( + catalog, + selectedBaseKey, + selectedLibraries, + selectedExtensions, + selectedAccess, + selectedAccessExtensions, + ); + + ctx.param.framework = framework; + ctx.param.base = selectedBaseKey; + ctx.param.extensions = selectedExtensions; + ctx.param.libraries = selectedLibraries; + ctx.param.access = selectedAccess; + ctx.param.accessExtensions = selectedAccessExtensions; + + ctx.config.bases = catalog; + ctx.state.entry = { + success: true, + result: { + framework, + selectedBaseKey, + selectedBaseLabel: selectedBase.label, + selectedLibraries, + selectedAccess, + selectedExtensions: selection.selectedExtensions, + selectedAccessExtensions: selection.selectedAccessExtensions, + requiredFacets: Object.keys(selection.requiredFacets), + availableLibraryFacets: Object.keys(availableLibraryFacets), + }, + error: null, + }; + + return ctx; + }, +}; diff --git a/cli/src/modules/init/prompts.ts b/cli/src/modules/init/prompts.ts new file mode 100644 index 00000000..e4118cb8 --- /dev/null +++ b/cli/src/modules/init/prompts.ts @@ -0,0 +1,131 @@ +import { BaseDefinition } from "../config/types"; +import { PromptApi } from "./types"; + +/** A choice option for an @inquirer/prompts select or checkbox prompt. */ +export type PromptChoice = { + name: string; + value: Value; +}; + +/** + * Dynamically imports and returns the @inquirer/prompts API. + * Uses dynamic import to avoid bundling the dependency when unused. + * + * @returns The prompt API with input, select, checkbox, and confirm methods. + */ +export async function loadPrompts(): Promise { + return (await import("@inquirer/prompts")) as unknown as PromptApi; +} + +/** + * Converts an array of facet names into prompt choice objects. + * + * @param facetNames - The facet names to convert. + * @returns Array of prompt choices with name and value set to the facet name. + */ +export function toFacetChoices(facetNames: string[]): PromptChoice[] { + return facetNames.map((facetName) => ({ + name: facetName, + value: facetName, + })); +} + +/** + * Returns ownership base choices for the select prompt, with "None" as the first option. + * + * @param accessBases - Available access bases from the catalog. + * @returns Choices for ownership selection (includes undefined for "None"). + */ +export function getOwnershipChoices( + accessBases: Record, +): PromptChoice[] { + return [ + { name: "None", value: undefined }, + ...Object.entries(accessBases) + .filter(([, definition]) => definition.accessType === "ownership") + .map(([baseKey, definition]) => ({ + name: definition.label, + value: baseKey, + })), + ]; +} + +/** + * Returns optional extension facets available for the selected ownership base. + * + * @param accessBases - Available access bases from the catalog. + * @param selectedOwnership - The selected ownership base key, or undefined. + * @returns Checkbox choices for ownership extensions, or empty if none selected. + */ +export function getOwnershipExtensionChoices( + accessBases: Record, + selectedOwnership: string | undefined, +): PromptChoice[] { + if (!selectedOwnership) return []; + return toFacetChoices(Object.keys(accessBases[selectedOwnership]?.optional ?? {})); +} + +/** + * Returns role-based access control base choices (excludes ownership types), with "None" as the first option. + * + * @param accessBases - Available access bases from the catalog. + * @returns Choices for role-based access control (includes undefined for "None"). + */ +export function getRoleAccessChoices( + accessBases: Record, +): PromptChoice[] { + return [ + { name: "None", value: undefined }, + ...Object.entries(accessBases) + .filter(([, definition]) => definition.accessType !== "ownership") + .map(([baseKey, definition]) => ({ + name: definition.label, + value: baseKey, + })), + ]; +} + +/** + * Returns optional extension facets available across all selected role-based access bases. + * + * @param accessBases - Available access bases from the catalog. + * @param selectedRoleAccess - Key of the selected role-based access base, or undefined. + * @returns Deduplicated checkbox choices for access control extensions. + */ +export function getRoleAccessExtensionChoices( + accessBases: Record, + selectedRoleAccess: string | undefined, +): PromptChoice[] { + if (!selectedRoleAccess) return []; + return toFacetChoices(Object.keys(accessBases[selectedRoleAccess]?.optional ?? {})); +} + +/** Custom theme for checkbox prompts with simplified icons, no help tip, and "None" when empty. */ +export const checkboxTheme = { + prefix: "", + icon: { + checked: "[✓]", + unchecked: "[ ]", + cursor: ">", + disabledChecked: "[✓]", + disabledUnchecked: "[ ]", + }, + style: { + keysHelpTip: () => undefined, + renderSelectedChoices: (selected: readonly { short: string }[]) => { + if (selected.length === 0) return "None"; + return selected.map((c) => c.short).join(", "); + }, + }, +} as const; + +/** Custom theme for select prompts with simplified cursor and no help tip. */ +export const selectTheme = { + prefix: "", + icon: { + cursor: ">", + }, + style: { + keysHelpTip: () => undefined, + }, +} as const; diff --git a/cli/src/modules/init/types.ts b/cli/src/modules/init/types.ts new file mode 100644 index 00000000..97d065f4 --- /dev/null +++ b/cli/src/modules/init/types.ts @@ -0,0 +1,80 @@ +export type PromptApi = { + checkbox: ( + config: { + message: string; + choices: readonly { name: string; value: Value; checked?: boolean }[]; + theme?: { + prefix?: string | { idle?: string; done?: string }; + icon?: { + checked?: string; + unchecked?: string; + cursor?: string; + disabledChecked?: string; + disabledUnchecked?: string; + }; + style?: { + keysHelpTip?: (keys: [key: string, action: string][]) => string | undefined; + }; + }; + }, + ) => Promise; + select: ( + config: { + message: string; + choices: readonly { name: string; value: Value }[]; + default?: Value; + theme?: { + prefix?: string | { idle?: string; done?: string }; + icon?: { + cursor?: string; + }; + style?: { + keysHelpTip?: (keys: [key: string, action: string][]) => string | undefined; + }; + }; + }, + ) => Promise; + input: (config: { + message: string; + default?: string; + theme?: { + prefix?: string | { idle?: string; done?: string }; + }; + }) => Promise; + confirm: (config: { + message: string; + default?: boolean; + theme?: { + prefix?: string | { idle?: string; done?: string }; + }; + }) => Promise; +}; + +export type InitOptions = { + projectName: string; + base: string; + libraries: string[]; + extensions: string[]; + ownership: string; + ownershipExtensions: string[]; + accessControl: string[]; + accessControlExtensions: string[]; + framework: string; + outDir: string; + installDeps: boolean; + yes: boolean; +}; + +export type AccessFlagSelection = { + selectedOwnership: string[]; + selectedRoleAccess: string[]; + selectedOwnershipExtensions: string[]; + selectedRoleAccessExtensions: string[]; + selectedAccess: string[]; + selectedAccessExtensions: string[]; +}; + +export type FrameworkDependencies = { + deps: { name: string; version: string }[]; + packageType: string; +}; \ No newline at end of file diff --git a/cli/src/modules/pipelineBuilder/module.ts b/cli/src/modules/pipelineBuilder/module.ts new file mode 100644 index 00000000..6a2caad5 --- /dev/null +++ b/cli/src/modules/pipelineBuilder/module.ts @@ -0,0 +1,59 @@ +import { ComposeContext } from "../../context/types"; +import { InitPipeline } from "../../pipelines/initPipeline"; +import { InfoPipeline } from "../../pipelines/infoPipeline"; + +/** + * Pipeline builder module that routes CLI commands to their corresponding pipelines. + * + * Dispatches by command name (`init`, `validate`). + * + * Used by {@link EntryPipeline} for top-level command routing. + */ +export const PipelineBuilderModule = { + /** + * Routes the execution context to the appropriate pipeline based on the + * command in `ctx.param.command`. + * + * Unknown or missing command — sets `ctx.state.commandRouting` with a + * `COMMAND_NOT_SUPPORTED` error. + * + * @param ctx - The compose context with `param.command` populated by the args parser. + * @returns The context enriched with `commandSelected` or `commandRouting` state. + */ + async route(ctx: ComposeContext): Promise { + switch (ctx.param.command) { + case "init": + ctx.state.commandSelected = { + success: true, + result: { command: ctx.param.command, framework: ctx.param.framework }, + error: null, + }; + return InitPipeline.execute(ctx); + case "validate": + ctx.state.commandSelected = { + success: true, + result: { command: ctx.param.command }, + error: null, + }; + return ctx; + case "info": + ctx.state.commandSelected = { + success: true, + result: { command: ctx.param.command }, + error: null, + }; + return InfoPipeline.execute(ctx); + default: + ctx.state.commandRouting = { + success: false, + result: null, + error: { + code: "COMMAND_NOT_SUPPORTED", + message: `Unknown command: ${ctx.param.command}. Run 'compose --help' for usage.`, + nativeError: null, + }, + }; + return ctx; + } + }, +}; diff --git a/cli/src/modules/preflight/module.ts b/cli/src/modules/preflight/module.ts new file mode 100644 index 00000000..2ce99490 --- /dev/null +++ b/cli/src/modules/preflight/module.ts @@ -0,0 +1,36 @@ +import { ComposeContext } from "../../context/types"; +import { isBinaryInPath } from "../../utils/exec"; + +/** + * Pre-flight checks that verify required toolchain binaries are available. + * + * Before scaffolding begins, this module ensures the user's system has the + * necessary binaries in `PATH` for the selected framework. + */ +export const PreflightModule = { + /** + * Verifies that the required binary for the selected framework exists in PATH. + * + * - Foundry: checks for `forge`. + * - Hardhat with `installDeps !== false`: checks for `npm`. + * + * Throws an error with an install suggestion if the binary is not found. + * + * @param ctx - The compose context with `param.framework` and `param.installDeps`. + * @returns The context unchanged (validation is pass/fail via throw). + */ + async check(ctx: ComposeContext): Promise { + const framework = String(ctx.param.framework ?? "foundry").toLowerCase(); + + if (framework === "foundry") { + await isBinaryInPath("forge"); + } else if (framework === "hardhat") { + const shouldInstallDeps = ctx.param.installDeps !== false; + if (shouldInstallDeps) { + await isBinaryInPath("npm"); + } + } + + return ctx; + }, +}; \ No newline at end of file diff --git a/cli/src/modules/projectDir/module.ts b/cli/src/modules/projectDir/module.ts new file mode 100644 index 00000000..4a5c9f73 --- /dev/null +++ b/cli/src/modules/projectDir/module.ts @@ -0,0 +1,58 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { ComposeContext } from "../../context/types"; +import { pathExists, isDirectoryEmpty } from "../../utils/files"; + +/** + * Resolves and validates the target project directory. + * + * Determines the output path from `outDir` and `projectName`, then ensures + * the directory is either empty or non-existent before scaffolding begins. + */ +export const ProjectDirModule = { + /** + * Resolves the project root directory path. + * + * The root is resolved as `outDir/projectName` (defaulting to cwd and + * `my-diamond` respectively). + * + * @param ctx - The compose context with `param.projectName` and `param.outDir`. + * @returns The context with `param.projectRoot` set. + */ + async resolve(ctx: ComposeContext): Promise { + const projectName = String(ctx.param.projectName ?? "my-diamond"); + const outDir = String(ctx.param.outDir ?? process.cwd()); + ctx.param.projectRoot = path.resolve(outDir, projectName); + + return ctx; + }, + + /** + * Validates that the resolved project root is empty or does not exist. + * + * If the directory does not exist it is created with `recursive: true`. + * If it exists but contains non-`.git` entries, an error is thrown. + * + * @param ctx - The compose context with `param.projectRoot` already resolved. + * @returns The context unchanged (validation is pass/fail via throw). + */ + async validate(ctx: ComposeContext): Promise { + const projectRoot = String(ctx.param.projectRoot ?? ""); + + if (!projectRoot) { + throw new Error("Project root is not defined."); + } + + const exists = await pathExists(projectRoot); + if (exists) { + const isEmpty = await isDirectoryEmpty(projectRoot, [".git"]); + if (!isEmpty) { + throw new Error(`Target directory is not empty: ${projectRoot}`); + } + } else { + await fs.mkdir(projectRoot, { recursive: true }); + } + + return ctx; + }, +}; \ No newline at end of file diff --git a/cli/src/modules/scaffolding/facetSelection.ts b/cli/src/modules/scaffolding/facetSelection.ts new file mode 100644 index 00000000..36bfbf0e --- /dev/null +++ b/cli/src/modules/scaffolding/facetSelection.ts @@ -0,0 +1,93 @@ +import { BasesCatalog, FacetEntry } from "../config/types"; +import { resolveCatalogSelection } from "../config/module"; +import { SelectedFacet } from "./types"; +import { ComposeContext } from "../../context/types"; +import { isDeepEqual } from "../../utils/objects"; + +/** + * Collects all selected facets from the catalog based on the user's choices, + * ordered by source priority: diamond-required, library-required, base-required, + * access-required, then optional/extension facets. + * + * Detects conflicting definitions for the same facet name across selected bases. + * + * @param ctx - The compose context with CLI parameters and loaded catalog. + * @returns Ordered array of selected facets with their source classification. + * @throws {Error} If a facet has conflicting definitions across bases. + */ +export function getSelectedFacets(ctx: ComposeContext): SelectedFacet[] { + const catalog = ctx.config.bases as BasesCatalog; + const selectedBaseKey = String(ctx.param.base ?? ""); + const selectedLibraryNames = new Set((ctx.param.libraries as string[] | undefined) ?? []); + const selectedExtensionNames = new Set((ctx.param.extensions as string[] | undefined) ?? []); + const selectedAccessNames = new Set((ctx.param.access as string[] | undefined) ?? []); + const selectedAccessExtensionNames = new Set((ctx.param.accessExtensions as string[] | undefined) ?? []); + const selection = resolveCatalogSelection( + catalog, + selectedBaseKey, + [...selectedLibraryNames], + [...selectedExtensionNames], + [...selectedAccessNames], + [...selectedAccessExtensionNames], + ); + + const selected: SelectedFacet[] = []; + const selectedNames = new Map(); + const addSelectedFacet = (facet: SelectedFacet): void => { + const existing = selectedNames.get(facet.name); + if (existing) { + if (!isDeepEqual(existing, facet.entry)) { + throw new Error(`Facet ${facet.name} has conflicting definitions across selected bases.`); + } + return; + } + selectedNames.set(facet.name, facet.entry); + selected.push(facet); + }; + + for (const [name, entry] of Object.entries(catalog.globals.diamond?.required ?? {})) { + addSelectedFacet({ name, entry, source: "diamond-required" }); + } + + for (const [name, entry] of Object.entries(catalog.globals.libraries?.required ?? {})) { + addSelectedFacet({ name, entry, source: "library-required" }); + } + + for (const [name, entry] of Object.entries(selection.selectedBase.required)) { + addSelectedFacet({ name, entry, source: "base-required" }); + } + + for (const accessBase of selection.selectedAccessBases) { + for (const [name, entry] of Object.entries(accessBase.required)) { + addSelectedFacet({ name, entry, source: "access-required" }); + } + } + + for (const [name, entry] of Object.entries(catalog.globals.diamond?.optional ?? {})) { + if (selection.selectedGlobalLibraries.includes(name)) { + addSelectedFacet({ name, entry, source: "diamond-optional" }); + } + } + + for (const [name, entry] of Object.entries(catalog.globals.libraries?.optional ?? {})) { + if (selection.selectedGlobalLibraries.includes(name)) { + addSelectedFacet({ name, entry, source: "library-optional" }); + } + } + + for (const [name, entry] of Object.entries(selection.selectedBase.optional)) { + if (selectedExtensionNames.has(name)) { + addSelectedFacet({ name, entry, source: "extension" }); + } + } + + for (const accessBase of selection.selectedAccessBases) { + for (const [name, entry] of Object.entries(accessBase.optional)) { + if (selectedAccessExtensionNames.has(name)) { + addSelectedFacet({ name, entry, source: "access-extension" }); + } + } + } + + return selected; +} diff --git a/cli/src/modules/scaffolding/module.ts b/cli/src/modules/scaffolding/module.ts new file mode 100644 index 00000000..ac8749ba --- /dev/null +++ b/cli/src/modules/scaffolding/module.ts @@ -0,0 +1,298 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { IFrameworkAdapter } from "../../adapters/interface/IFrameworkAdapter"; +import { ComposeContext, ModuleState } from "../../context/types"; +import { VERSION } from "../../utils/metadata"; +import { copyFileIfMissing, parsePackageName, resolveLocalSolidityImportClosure, toPosixPath } from "../../utils/files"; +import { extractSolidityContractBody, parseExportedSelectorSignatures, parseSolidityFunctions } from "../../utils/solidityText"; +import { contractNameFromSourcePath, isComposePackagePath, resolveCatalogSourceForRead } from "../../utils/soliditySources"; +import { SeedFile, FacetScanResult, ScaffoldMapEntry } from "./types"; +import { getSelectedFacets } from "./facetSelection"; +import { parseStorageLayouts } from "./storage"; +import { targetDirectoryForFacet } from "./paths"; + +export { getSelectedFacets } from "./facetSelection"; +export { targetDirectoryForFacet } from "./paths"; +export { parseStorageLayouts } from "./storage"; + +/** + * Scans selected Solidity facets and writes the final project configuration. + * + * Parses each facet's source file to extract contract names, functions, + * exported selectors, and storage layouts, then writes the assembled + * `compose.json` to the project root. + */ +export const ScaffoldingModule = { + /** + * Records the framework scaffold map so later modules can resolve generated files. + * + * @param ctx - The compose context to receive the scaffold map state. + * @param entries - The scaffold map entries returned by the framework adapter. + * @returns The context with `ctx.state.scaffoldMap` populated. + */ + recordScaffoldMap(ctx: ComposeContext, entries: ScaffoldMapEntry[]): ComposeContext { + ctx.state.scaffoldMap = { + success: true, + result: { entries }, + error: null, + }; + + return ctx; + }, + + /** + * Copies selected facet source files and their import closures into the project. + * + * Resolves each facet's source path, copies the file to the appropriate target + * directory (diamond/, libraries/, or facets/), and follows relative imports + * to copy transitive dependencies. + * + * @param ctx - The compose context with selected facets. + * @param contractSourceRoot - The framework's contract source root (e.g., src/ or contracts/). + * @returns The scaffold map entries for all copied facets. + */ + async copyFacets(ctx: ComposeContext, contractSourceRoot: string): Promise { + const selectedFacets = getSelectedFacets(ctx); + const localFacets = selectedFacets.filter((facet) => !isComposePackagePath(facet.entry.path)); + + const allSeeds: SeedFile[] = localFacets.map((facet) => ({ + source: resolveCatalogSourceForRead(facet.entry.path), + target: path.join(targetDirectoryForFacet(contractSourceRoot, facet), path.basename(facet.entry.path)), + })); + + const seedSources = allSeeds.map((x) => x.source); + const closure = await resolveLocalSolidityImportClosure(seedSources); + + const sourceToTarget = new Map(); + for (const seed of allSeeds) { + sourceToTarget.set(path.resolve(seed.source), seed.target); + } + + for (const file of closure) { + const directTarget = sourceToTarget.get(path.resolve(file)); + if (directTarget) { + await copyFileIfMissing(file, directTarget); + continue; + } + + const parentSeed = allSeeds.find((seed) => file.startsWith(path.dirname(path.resolve(seed.source)))); + const baseTargetDir = parentSeed ? path.dirname(parentSeed.target) : contractSourceRoot; + await copyFileIfMissing(file, path.join(baseTargetDir, path.basename(file))); + } + + const localTargetByFacetName = new Map(localFacets.map((facet, index) => [facet.name, allSeeds[index].target])); + const scaffoldMap: ScaffoldMapEntry[] = selectedFacets.map((facet) => { + const isPackageFacet = isComposePackagePath(facet.entry.path); + return { + facetName: facet.name, + contractName: contractNameFromSourcePath(facet.entry.path), + targetPath: isPackageFacet ? facet.entry.path : String(localTargetByFacetName.get(facet.name)), + origin: isPackageFacet ? "package" as const : "local" as const, + }; + }); + + return scaffoldMap; + }, + + /** + * Scans all selected facets for functions, exported selectors, and storage layouts. + * + * For each facet the source file is read and parsed for: + * - The contract name. + * - All public/external functions (name, signature, visibility). + * - Exported selector names from `exportSelectors()`. + * - Storage layouts via ERC-8042 annotations or slot-assignment inference. + * + * `missingExports` (functions not in `exportSelectors`) and `extraExports` + * (names in `exportSelectors` that don't match a function) are computed per + * facet. Results are stored in `ctx.state.facetScan`. + * + * @param ctx - The compose context with selected facets in `ctx.param`. + * @returns The context enriched with facet scan results. + */ + async scanSelectedFacets(ctx: ComposeContext, adapter: IFrameworkAdapter): Promise { + const selectedFacets = getSelectedFacets(ctx); + const results: FacetScanResult[] = []; + + for (const facet of selectedFacets) { + const resolvedPath = await adapter.resolveSoliditySourcePath(ctx, facet.entry.path); + const source = await fs.readFile(resolvedPath, "utf8"); + const contractBody = extractSolidityContractBody(source, facet.name); + if (contractBody === null) { + throw new Error(`Selected facet contract not found: ${facet.name} (${facet.entry.path})`); + } + + const functions = parseSolidityFunctions(contractBody); + const exportedSelectors = parseExportedSelectorSignatures(contractBody, functions); + const exportedSet = new Set(exportedSelectors); + const functionSignatures = new Set(functions.map((fn) => fn.signature)); + const warnings: string[] = []; + const storageScan = parseStorageLayouts(contractBody); + + if (exportedSelectors.length === 0) { + warnings.push("exportSelectors() was not found or did not export any this..selector entries."); + } + warnings.push(...storageScan.warnings); + + results.push({ + facetName: facet.name, + source: facet.source, + path: facet.entry.path, + contractName: facet.name, + functions, + exportedSelectors, + missingExports: functions.filter((fn) => !exportedSet.has(fn.signature)).map((fn) => fn.signature), + extraExports: exportedSelectors.filter((signature) => !functionSignatures.has(signature)), + storageLayouts: storageScan.layouts, + warnings, + }); + } + + ctx.state.facetScan = { + success: results.every((result) => result.missingExports.length === 0 && result.extraExports.length === 0), + result: { + facets: results, + facetCount: results.length, + selectorHashing: "not-computed", + onchain: false, + }, + error: null, + }; + + return ctx; + }, + + /** + * Builds the `compose.json` object from the scaffold map. + * + * Reads `ctx.state.scaffoldMap` (populated by `recordScaffoldMap`) to + * determine where each facet was placed. Derives contract paths relative to + * the project root and classifies each facet origin as "local" or "package". + * + * M1: All facets are "local" (copied into the project). The "package" origin + * is reserved for future use when facets reference the installed Compose + * library via imports instead of copying source files. + * + * @param ctx - The compose context with `state.scaffoldMap`, `param.projectRoot`, `param.framework`, `param.projectName`. + * @returns The context with `config.composeJson` populated. + */ + buildComposeJson(ctx: ComposeContext, contractSourceRoot: string): ComposeContext { + const framework = String(ctx.param.framework ?? "foundry"); + const projectName = String(ctx.param.projectName ?? "my-diamond"); + const root = String(ctx.param.projectRoot ?? ""); + const contractDir = toPosixPath(path.relative(root, contractSourceRoot)); + + const scaffoldMapState = ctx.state.scaffoldMap as ModuleState<{ entries: ScaffoldMapEntry[] }> | undefined; + const entries = scaffoldMapState?.result?.entries ?? []; + + const facetScanState = ctx.state.facetScan as ModuleState<{ facets: FacetScanResult[] }> | undefined; + const facetScanResults = facetScanState?.result?.facets ?? []; + + const facets: Record = {}; + for (const entry of entries) { + const relativePath = toPosixPath(path.relative(root, entry.targetPath)); + if (entry.origin === "package") { + const scanResult = facetScanResults.find((f) => f.facetName === entry.facetName); + const sourcePath = scanResult?.path ?? entry.contractName; + const packageName = parsePackageName(sourcePath); + facets[entry.facetName] = { + source: "package", + contract: entry.contractName, + package: packageName, + }; + } else { + facets[entry.facetName] = { + source: "local", + contract: `${relativePath}:${entry.contractName}`, + }; + } + } + + ctx.config.composeJson = { + project: projectName, + compose: VERSION, + framework, + diamonds: { + [projectName]: { + contract: `${contractDir}/Diamond.sol:Diamond`, + facets, + }, + }, + chains: { + local: { rpc: "http://127.0.0.1:8545", chainId: 31337 }, + }, + }; + + return ctx; + }, + + /** + * Validates that local facet files exist at their expected paths. + * + * After scaffolding, checks each facet with `source: "local"` in + * `compose.json` to verify the file was copied to the expected location. + * Stores warnings on `ctx.state.facetFileValidation` but does not block + * the pipeline. + * + * @param ctx - The compose context with `config.composeJson` and `param.projectRoot`. + * @returns The context with `state.facetFileValidation` populated. + */ + async validateLocalFacetFiles(ctx: ComposeContext): Promise { + const composeJson = ctx.config.composeJson as Record | undefined; + if (!composeJson) { + ctx.state.facetFileValidation = { + success: true, + result: { warnings: [] }, + error: null, + }; + return ctx; + } + + const root = String(ctx.param.projectRoot ?? ""); + const diamonds = composeJson.diamonds as Record }> | undefined; + const warnings: string[] = []; + + if (diamonds) { + for (const diamond of Object.values(diamonds)) { + for (const [name, facet] of Object.entries(diamond.facets)) { + if (facet.source !== "local") continue; + + const contractPath = facet.contract.split(":")[0]; + const fullPath = path.resolve(root, contractPath); + + try { + await fs.access(fullPath); + } catch { + warnings.push(`Local facet file not found: ${contractPath} (referenced by ${name})`); + } + } + } + } + + ctx.state.facetFileValidation = { + success: warnings.length === 0, + result: { warnings }, + error: null, + }; + + return ctx; + }, + + /** + * Writes the assembled `compose.json` to the project root. + * + * Serializes `ctx.config.composeJson` as pretty-printed JSON and writes it + * to `/compose.json`. + * + * @param ctx - The compose context with `param.projectRoot` and `config.composeJson`. + * @returns The context unchanged. + */ + async writeComposeConfig(ctx: ComposeContext): Promise { + const root = String(ctx.param.projectRoot ?? ""); + const composeJson = ctx.config.composeJson; + + await fs.writeFile(path.join(root, "compose.json"), `${JSON.stringify(composeJson, null, 2)}\n`, "utf8"); + + return ctx; + }, +}; diff --git a/cli/src/modules/scaffolding/paths.ts b/cli/src/modules/scaffolding/paths.ts new file mode 100644 index 00000000..63325214 --- /dev/null +++ b/cli/src/modules/scaffolding/paths.ts @@ -0,0 +1,22 @@ +import path from "node:path"; +import { SelectedFacet } from "./types"; + +/** + * Returns the target directory for a facet based on its source classification. + * Diamond facets go to `diamond/`, library facets to `libraries/`, others to `facets/`. + * + * @param contractSourceRoot - The root directory for contract source files. + * @param facet - The selected facet with source classification. + * @returns The absolute target directory path. + */ +export function targetDirectoryForFacet(contractSourceRoot: string, facet: SelectedFacet): string { + if (facet.source === "diamond-required" || facet.source === "diamond-optional") { + return path.join(contractSourceRoot, "diamond"); + } + + if (facet.source === "library-required" || facet.source === "library-optional") { + return path.join(contractSourceRoot, "libraries"); + } + + return path.join(contractSourceRoot, "facets"); +} diff --git a/cli/src/modules/scaffolding/storage.ts b/cli/src/modules/scaffolding/storage.ts new file mode 100644 index 00000000..e92c69e0 --- /dev/null +++ b/cli/src/modules/scaffolding/storage.ts @@ -0,0 +1,343 @@ +import { findSolidityClosingBrace, removeSolidityComments } from "../../utils/solidityText"; +import { escapeRegExp } from "../../utils/regex"; +import { dedupeBy } from "../../utils/arrays"; +import { StorageLayoutInfo } from "./types"; + +/** + * Parses storage layouts from Solidity source code, preferring ERC-8042 annotations + * and falling back to `.slot :=` assignment inference. + * + * @param source - The full Solidity source code. + * @returns An object with parsed layouts and any warnings encountered. + */ +export function parseStorageLayouts(source: string): { layouts: StorageLayoutInfo[]; warnings: string[] } { + const cleanSource = removeSolidityComments(source); + const layouts: StorageLayoutInfo[] = []; + const warnings: string[] = []; + const structs = parseStructs(cleanSource); + const annotationPattern = /@custom:storage-location\s+erc8042:([A-Za-z0-9_.:-]+)[\s\S]*?\bstruct\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/g; + let match: RegExpExecArray | null; + + while ((match = annotationPattern.exec(source)) !== null) { + layouts.push(...buildStorageLayouts(match[1], match[2], structs, "erc8042")); + } + + if (layouts.length > 0) { + return { layouts, warnings }; + } + + const inferredLayouts = parseSlotAssignmentLayouts(cleanSource, structs); + if (inferredLayouts.length > 0) { + warnings.push( + "Missing `@custom:storage-location` annotation -- storage slot inferred from `.slot :=` pattern. Add the annotation for reliable detection.", + ); + return { layouts: inferredLayouts, warnings }; + } + + warnings.push("Cannot determine storage layout -- no ERC-8042 annotation or recognized storage pattern found."); + return { layouts: [], warnings }; +} + +/** + * Parses all struct definitions from Solidity source, returning a map of + * struct name to its body content. + * + * @param source - The Solidity source code. + * @returns A map of struct names to their body strings. + */ +export function parseStructs(source: string): Map { + const structs = new Map(); + const structPattern = /\bstruct\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/g; + let match: RegExpExecArray | null; + + while ((match = structPattern.exec(source)) !== null) { + const bodyStart = structPattern.lastIndex; + const bodyEnd = findSolidityClosingBrace(source, bodyStart - 1); + if (bodyEnd === -1) { + continue; + } + + structs.set(match[1], source.slice(bodyStart, bodyEnd)); + structPattern.lastIndex = bodyEnd + 1; + } + + return structs; +} + +/** + * Builds a storage layout info entry from a slot string and struct name. + * + * @param slot - The storage slot identifier (e.g. "myNamespace" or "0x..."). + * @param structName - The struct name to build the layout for. + * @param structs - Map of all parsed structs. + * @param source - The detection source ("erc8042" or "slot-assignment"). + * @returns An array containing the single storage layout entry. + */ +export function buildStorageLayouts( + slot: string, + structName: string, + structs: Map, + source: StorageLayoutInfo["source"], +): StorageLayoutInfo[] { + const root = buildStructLayout(structName, structs); + return [ + { + slot, + layout: root, + source, + structName, + }, + ]; +} + +/** + * Parses storage layouts from `.slot :=` assembly patterns within functions. + * Infers slot namespaces from string literals, constants, or keccak256 expressions. + * + * @param source - The comment-stripped Solidity source code. + * @param structs - Map of all parsed structs. + * @returns Deduplicated array of storage layout entries. + */ +export function parseSlotAssignmentLayouts( + source: string, + structs: Map, +): StorageLayoutInfo[] { + const layouts: StorageLayoutInfo[] = []; + const functionPattern = /\bfunction\b[\s\S]*?\{[\s\S]*?\bassembly\s*\{[\s\S]*?\.slot\s*:=[\s\S]*?\}[\s\S]*?\n\s*\}/g; + let match: RegExpExecArray | null; + + while ((match = functionPattern.exec(source)) !== null) { + const functionSource = match[0]; + const structName = parseReturnedStorageStruct(functionSource); + const slotExpression = parseSlotAssignmentExpression(functionSource); + + if (!structName || !slotExpression) { + continue; + } + + const slot = resolveSlotNamespace(slotExpression, functionSource, source); + if (!slot || !structs.has(structName)) { + continue; + } + + layouts.push(...buildStorageLayouts(slot, structName, structs, "slot-assignment")); + } + + return dedupeStorageLayouts(layouts); +} + +/** + * Extracts the struct type name from a function's return statement + * (e.g. `returns (MyStruct storage self)`). + * + * @param functionSource - The function body source code. + * @returns The struct type name, or null if not found. + */ +export function parseReturnedStorageStruct(functionSource: string): string | null { + const match = functionSource.match(/\breturns\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s+storage\s+[A-Za-z_][A-Za-z0-9_]*\s*\)/); + return match?.[1] ?? null; +} + +/** + * Extracts the slot assignment expression from a `.slot :=` pattern. + * + * @param functionSource - The function body source code. + * @returns The slot expression (identifier, string, or hex literal), or null. + */ +export function parseSlotAssignmentExpression(functionSource: string): string | null { + const match = functionSource.match(/\.slot\s*:=\s*([A-Za-z_][A-Za-z0-9_]*|"[^"]+"|'[^']+'|0x[0-9a-fA-F]+)\b/); + return match?.[1] ?? null; +} + +/** + * Resolves a slot expression to its namespace string by checking for + * string literals, constants, local assignments, or keccak256 expressions. + * + * @param expression - The raw slot expression from assembly. + * @param functionSource - The enclosing function's source code. + * @param fullSource - The full contract source code for constant resolution. + * @returns The resolved namespace string, or null if unresolvable. + */ +export function resolveSlotNamespace( + expression: string, + functionSource: string, + fullSource: string, +): string | null { + const directString = expression.match(/^["']([^"']+)["']$/); + if (directString) { + return directString[1]; + } + + const directConstant = resolveConstantNamespace(expression, fullSource); + if (directConstant) { + return directConstant; + } + + const localAssignmentPattern = new RegExp(`\\bbytes32\\s+${escapeRegExp(expression)}\\s*=\\s*([^;]+);`); + const localAssignment = functionSource.match(localAssignmentPattern); + if (!localAssignment) { + return null; + } + + const localExpression = localAssignment[1].trim(); + const localKeccak = parseKeccakNamespace(localExpression); + if (localKeccak) { + return localKeccak; + } + + return resolveConstantNamespace(localExpression, fullSource); +} + +/** + * Resolves a constant's value by looking up its declaration in the source + * and extracting the keccak256 namespace string. + * + * @param name - The constant variable name. + * @param source - The full contract source code. + * @returns The keccak256 namespace string, or null if not found. + */ +export function resolveConstantNamespace(name: string, source: string): string | null { + const constantPattern = new RegExp(`\\bbytes32\\s+(?:internal\\s+|private\\s+|public\\s+)?constant\\s+${escapeRegExp(name)}\\s*=\\s*([^;]+);`); + const match = source.match(constantPattern); + if (!match) { + return null; + } + + return parseKeccakNamespace(match[1]); +} + +/** + * Extracts the string argument from a keccak256() expression. + * + * @param expression - The expression to parse. + * @returns The namespace string, or null if not a keccak256 call. + */ +export function parseKeccakNamespace(expression: string): string | null { + const match = expression.match(/\bkeccak256\s*\(\s*["']([^"']+)["']\s*\)/); + return match?.[1] ?? null; +} + +/** + * Deduplicates storage layouts by their slot, struct name, and layout fields. + * + * @param layouts - Array of storage layouts that may contain duplicates. + * @returns Deduplicated array preserving first occurrence order. + */ +export function dedupeStorageLayouts(layouts: StorageLayoutInfo[]): StorageLayoutInfo[] { + return dedupeBy(layouts, (layout) => `${layout.slot}:${layout.structName ?? ""}:${layout.layout.join(",")}`); +} + +/** + * Recursively builds a flattened storage layout array from a struct definition. + * Nested structs are inlined; primitive types become storage type tokens. + * + * @param structName - The root struct name to build the layout for. + * @param structs - Map of all parsed structs. + * @returns Flattened array of storage type tokens. + */ +export function buildStructLayout( + structName: string, + structs: Map, +): string[] { + const body = structs.get(structName); + if (!body) { + return []; + } + + const layout: string[] = []; + + for (const field of parseStructFields(body)) { + const fieldType = normalizeStorageType(field.type); + + if (structs.has(fieldType)) { + const inlineLayout = buildStructLayout(fieldType, structs); + layout.push(...inlineLayout); + continue; + } + + layout.push(storageTypeToken(fieldType)); + } + + return layout; +} + +/** + * Parses the body of a Solidity struct into typed field entries. + * + * @param body - The struct body content (between braces). + * @returns Array of parsed fields with type and name. + */ +export function parseStructFields(body: string): { type: string; name: string }[] { + return body + .split(";") + .map((rawField) => rawField.trim()) + .filter(Boolean) + .map((field) => field.replace(/\s+/g, " ")) + .map((field) => { + const match = field.match(/^(.+)\s+([A-Za-z_][A-Za-z0-9_]*)$/); + if (!match) { + return null; + } + + return { type: match[1], name: match[2] }; + }) + .filter((field): field is { type: string; name: string } => field !== null); +} + +/** + * Normalizes a Solidity type string by removing data location and index modifiers. + * + * @param type - The raw type string. + * @returns The normalized type string. + */ +export function normalizeStorageType(type: string): string { + return type + .replace(/\b(calldata|memory|storage|indexed)\b/g, "") + .replace(/\s+/g, " ") + .trim(); +} + +/** + * Converts a Solidity type to a canonical storage type token. + * Normalizes uint/int shorthand, strips variable names, and removes whitespace. + * + * @param type - The raw Solidity type string. + * @returns The canonical storage type token. + */ +export function storageTypeToken(type: string): string { + let normalized = normalizeStorageType(type) + .replace(/\buint\b/g, "uint256") + .replace(/\bint\b/g, "int256") + .replace(/\s+/g, " ") + .trim(); + + normalized = stripStorageVariableNames(normalized); + normalized = normalized + .replace(/\s*=>\s*/g, "=>") + .replace(/\s*,\s*/g, ",") + .replace(/\s+/g, ""); + + return normalized; +} + +/** + * Removes variable names from a Solidity type expression, keeping only + * the type structure (handles mappings, arrays, and nested types). + * + * @param type - The type string potentially containing variable names. + * @returns The type string with variable names removed. + */ +export function stripStorageVariableNames(type: string): string { + let current = type; + let previous: string; + + do { + previous = current; + current = current.replace( + /\b([A-Za-z_][A-Za-z0-9_]*(?:[0-9]+)?(?:\[[^\]]*\])?)\s+[A-Za-z_][A-Za-z0-9_]*(?=\s*(?:=>|,|\)|$))/g, + "$1", + ); + } while (current !== previous); + + return current; +} diff --git a/cli/src/modules/scaffolding/types.ts b/cli/src/modules/scaffolding/types.ts new file mode 100644 index 00000000..06b49fe3 --- /dev/null +++ b/cli/src/modules/scaffolding/types.ts @@ -0,0 +1,52 @@ +import { FacetEntry } from "../config/types"; +import { SolidityFunctionInfo } from "../../utils/solidityText"; + +export type SeedFile = { + source: string; + target: string; +}; + +export type SelectedFacetSource = + | "diamond-required" + | "diamond-optional" + | "library-required" + | "base-required" + | "access-required" + | "library-optional" + | "extension" + | "access-extension"; + +export type SelectedFacet = { + name: string; + source: SelectedFacetSource; + entry: FacetEntry; +}; + +export type StorageLayoutInfo = { + slot: string; + layout: string[]; + source: "erc8042" | "slot-assignment"; + structName: string | null; +}; + +export type FacetScanResult = { + facetName: string; + source: SelectedFacetSource; + path: string; + contractName: string | null; + functions: SolidityFunctionInfo[]; + exportedSelectors: string[]; + missingExports: string[]; + extraExports: string[]; + storageLayouts: StorageLayoutInfo[]; + warnings: string[]; +}; + +export type FacetOrigin = "local" | "package"; + +export type ScaffoldMapEntry = { + facetName: string; + contractName: string; + targetPath: string; + origin: FacetOrigin; +}; diff --git a/cli/src/modules/terminalOutput/module.ts b/cli/src/modules/terminalOutput/module.ts new file mode 100644 index 00000000..b2bc04da --- /dev/null +++ b/cli/src/modules/terminalOutput/module.ts @@ -0,0 +1,203 @@ +import { ComposeContext } from "../../context/types"; +import { BasesCatalog } from "../config/types"; +import { cyan, dim, green, red, yellow } from "../../utils/terminal"; +import { COMPOSE_HEADER, COMPOSE_DOCS_URL } from "../../utils/metadata"; +import { + getFacetScanState, + getSelectorExportValidationState, + getSelectorCollisionValidationState, + getIdentifierCollisionValidationState, +} from "../validation/module"; +import { FacetScanWarning } from "../validation/types"; + +/** + * Terminal UI module for CLI output formatting. + * + * Provides methods for rendering the welcome header, help text, validation + * reports, success messages, and validation output. All output is colorized + * using the terminal utility helpers. + */ +export const TerminalOutputModule = { + /** + * Prints the Compose welcome banner and documentation URL. + */ + showComposeHeader() { + console.log(cyan(COMPOSE_HEADER)); + console.log(cyan("Scaffold your diamond smart contracts project with Compose")); + console.log(cyan(`Explore our library: ${COMPOSE_DOCS_URL}\n`)); + }, + + /** + * Displays a dimmed list of dependencies that will be installed. + * + * @param deps - Array of dependency objects with name and version. + * @param packageType - Label for the package type (e.g. "npm packages", "forge packages"). + */ + showDependencies(deps: { name: string; version: string }[], packageType: string): void { + console.log(dim(`\nThe following ${packageType} will be installed:\n`)); + for (const dep of deps) { + console.log(dim(` ${dep.name} ${dep.version}`)); + } + console.log(""); + }, + + + + /** + * Renders validation warnings and fail-fast error reports. + * + * Displays facet scan warnings (yellow), then checks for selector export + * issues, selector collisions, and identifier collisions in order. Each + * failure is printed in red with details and the method returns early. + * + * @param ctx - The compose context with validation state populated. + * @returns The context unchanged. + */ + async showReport(ctx: ComposeContext): Promise { + const facetScan = getFacetScanState(ctx); + const scanWarnings = (facetScan?.result?.facets ?? []) + .map((facet: FacetScanWarning) => facet) + .filter((facet: FacetScanWarning) => facet.warnings.length > 0); + + if (scanWarnings.length > 0) { + console.warn(yellow("\nValidation warnings")); + for (const facet of scanWarnings) { + console.warn(`\n${facet.facetName}`); + console.warn(` ${facet.path}`); + for (const warning of facet.warnings) { + console.warn(` ${warning}`); + } + } + } + + const selectorExportValidation = getSelectorExportValidationState(ctx); + + if (selectorExportValidation && !selectorExportValidation.success) { + console.error(red("\nValidation failed")); + console.error(red(selectorExportValidation.error?.message ?? "Validation failed.")); + + for (const issue of selectorExportValidation.result?.issues ?? []) { + console.error(`\n${issue.facetName}`); + console.error(` ${issue.path}`); + + if (issue.missingExports.length > 0) { + console.error(` Missing exports: ${issue.missingExports.join(", ")}`); + } + + if (issue.extraExports.length > 0) { + console.error(` Extra exports: ${issue.extraExports.join(", ")}`); + } + } + + return ctx; + } + + const selectorCollisionValidation = getSelectorCollisionValidationState(ctx); + + if (selectorCollisionValidation && !selectorCollisionValidation.success) { + console.error(red("\nValidation failed")); + console.error(red(selectorCollisionValidation.error?.message ?? "Validation failed.")); + + for (const collision of selectorCollisionValidation.result?.collisions ?? []) { + console.error(`\n${collision.selector}`); + for (const owner of collision.owners) { + console.error(` ${owner.facetName}: ${owner.signature}`); + console.error(` ${owner.path}`); + } + } + + return ctx; + } + + const identifierCollisionValidation = getIdentifierCollisionValidationState(ctx); + + if (identifierCollisionValidation && !identifierCollisionValidation.success) { + console.error(red("\nValidation failed")); + console.error(red(identifierCollisionValidation.error?.message ?? "Validation failed.")); + + for (const collision of identifierCollisionValidation.result?.collisions ?? []) { + console.error(`\n${collision.identifier}`); + for (const owner of collision.owners) { + console.error(` ${owner.facetName}: [${owner.layout.join(", ")}]`); + console.error(` ${owner.path}`); + } + } + } + + return ctx; + }, + + /** + * Prints the success message with framework-specific next steps. + * + * Displays the project name, scaffolded path, and a numbered list of + * next-step commands (e.g. `forge build && forge test` for Foundry, + * `npx hardhat compile && npx hardhat test` for Hardhat). Adjusts steps + * based on whether `installDeps` is enabled. + * + * @param ctx - The compose context with `param.projectName`, `param.projectRoot`, and `param.framework`. + */ + showSuccess(ctx: ComposeContext): void { + const projectName = String(ctx.param.projectName ?? "my-diamond"); + const projectRoot = String(ctx.param.projectRoot ?? ""); + + console.log(green(`\n✔`) + ` Project "${projectName}" scaffolded in "${projectRoot}"\n`); + console.log(green("Next steps:")); + + let stepCount = 1; + if (projectRoot !== process.cwd()) { + console.log(green(`${stepCount}.`) + ` cd ${projectName}`); + stepCount++; + } + + const framework = String(ctx.param.framework ?? "foundry"); + if (framework === "foundry") { + const installDeps = ctx.param.installDeps !== false; + if (installDeps) { + console.log(green(`${stepCount}.`) + ` forge build && forge test`); + } else { + console.log(green(`${stepCount}.`) + ` forge install Perfect-Abstractions/Compose`); + console.log(green(`${stepCount + 1}.`) + ` forge build && forge test`); + } + } else if (framework === "hardhat") { + const installDeps = ctx.param.installDeps !== false; + if (installDeps) { + console.log(green(`${stepCount}.`) + ` npx hardhat compile && npx hardhat test`); + } else { + console.log(green(`${stepCount}.`) + ` npm install`); + console.log(green(`${stepCount + 1}.`) + ` npx hardhat compile && npx hardhat test`); + } + } + + console.log(""); + console.log(green("You're all set. We hope you'll Compose something great!\n")); + console.log(yellow(`If this helped you, please give us a star on GitHub\n`) + `✨ https://github.com/Perfect-Abstractions/Compose ✨\n`); + console.log(`Please report any issues or feedback:\nhttps://github.com/Perfect-Abstractions/Compose/issues\n`); + }, + + /** + * Displays available Compose bases with their required and optional facets. + * + * Reads the bases catalog from `ctx.config.bases` and prints each feature + * with its label, required facets, and optional facets. + * + * @param ctx - The compose context with the loaded bases catalog. + */ + showTemplates(ctx: ComposeContext): void { + const catalog = ctx.config.bases as BasesCatalog; + const features = catalog.features; + + console.log("\nAvailable Compose bases:\n"); + + Object.entries(features).forEach(([key, definition]) => { + console.log(`${definition.label} (${key})`); + console.log(` Required: ${Object.keys(definition.required).join(", ") || "(none)"}`); + if (Object.keys(definition.optional).length > 0) { + console.log(` Optional: ${Object.keys(definition.optional).join(", ")}`); + } + console.log(""); + }); + + console.log("\nTo select a base for your project, use --base \n"); + }, +}; \ No newline at end of file diff --git a/cli/src/modules/testGeneration/model.ts b/cli/src/modules/testGeneration/model.ts new file mode 100644 index 00000000..8c12562c --- /dev/null +++ b/cli/src/modules/testGeneration/model.ts @@ -0,0 +1,62 @@ +import path from "node:path"; +import { ComposeContext, ModuleState } from "../../context/types"; +import { TestFacetEntry, TestGenerationModel } from "./types"; + +/** Result shape from the deploy script generation step. */ +type DeployScriptResult = { + outputPath: string; + facets: { + facetName: string; + contractName: string; + importPath: string; + group: string; + }[]; + framework: string; + toolbox: string | null; +}; + +/** + * Extracts the deploy script generation result from the compose context. + * + * @param ctx - The compose context with deploy script state. + * @returns The deploy script result. + * @throws {Error} If deploy script generation is missing or failed. + */ +function getDeployResult(ctx: ComposeContext): DeployScriptResult { + const state = ctx.state.generateDeployScript as ModuleState | undefined; + if (!state?.success || !state.result) { + throw new Error("Cannot generate test: deploy script generation is missing."); + } + return state.result; +} + +/** + * Resolves the test generation model by extracting facet entries from the + * deploy script result. + * + * @param ctx - The compose context with deploy script generation state. + * @param testRoot - Directory where the test file will be written. + * @param outputFileName - Name of the output test file. + * @returns The test generation model with output path and facet entries. + * @throws {Error} If deploy script generation is missing. + */ +export function resolveTestGenerationModel( + ctx: ComposeContext, + testRoot: string, + outputFileName: string, +): TestGenerationModel { + const deployResult = getDeployResult(ctx); + + const facets: TestFacetEntry[] = deployResult.facets.map((facet) => ({ + facetName: facet.facetName, + contractName: facet.contractName, + importPath: facet.importPath, + group: facet.group as TestFacetEntry["group"], + })); + + return { + outputPath: path.join(testRoot, outputFileName), + facets, + facetCount: facets.length, + }; +} diff --git a/cli/src/modules/testGeneration/module.ts b/cli/src/modules/testGeneration/module.ts new file mode 100644 index 00000000..d2d51c06 --- /dev/null +++ b/cli/src/modules/testGeneration/module.ts @@ -0,0 +1,58 @@ +import { ComposeContext } from "../../context/types"; +import { resolveTestGenerationModel } from "./model"; +import { + renderFoundryTest, + renderHardhatEthersTest, + renderHardhatViemTest, +} from "./renderers"; +import { writeFileIfMissing } from "../../utils/files"; + +/** + * Module responsible for generating framework-specific Diamond test files. + */ +export const TestGenerationModule = { + /** + * Generates a test file for the selected framework and toolbox, + * writes it to disk if missing, and updates the compose context state. + * + * @param ctx - The compose context with project parameters and state. + * @param testRoot - Directory where the test file will be written. + * @returns The updated compose context with generation results. + * @throws {Error} If the framework is unsupported or file operations fail. + */ + async generateTestFile( + ctx: ComposeContext, + testRoot: string, + ): Promise { + const framework = String(ctx.param.framework ?? "foundry"); + const toolbox = String(ctx.param.toolbox ?? "ethers"); + const outputFileName = framework === "foundry" ? "Diamond.t.sol" : "Diamond.ts"; + const model = resolveTestGenerationModel(ctx, testRoot, outputFileName); + let source: string; + + if (framework === "foundry") { + source = await renderFoundryTest(model); + } else if (framework === "hardhat" && toolbox === "viem") { + source = await renderHardhatViemTest(model); + } else if (framework === "hardhat") { + source = await renderHardhatEthersTest(model); + } else { + throw new Error(`Cannot generate test: unsupported framework ${framework}.`); + } + + await writeFileIfMissing(model.outputPath, source); + + ctx.state.generateTestFile = { + success: true, + result: { + outputPath: model.outputPath, + facetCount: model.facetCount, + framework, + toolbox: framework === "hardhat" ? toolbox : null, + }, + error: null, + }; + + return ctx; + }, +}; diff --git a/cli/src/modules/testGeneration/renderers.ts b/cli/src/modules/testGeneration/renderers.ts new file mode 100644 index 00000000..dff21314 --- /dev/null +++ b/cli/src/modules/testGeneration/renderers.ts @@ -0,0 +1,137 @@ +import { TestFacetEntry, TestGenerationModel } from "./types"; +import { toCamelCase } from "../../utils/strings"; +import { loadTemplate } from "../../utils/codegen"; + +/** + * Checks if an import path refers to an npm package (starts with "@"). + * + * @param importPath - The import path to check. + * @returns True if the path is a package import. + */ +function isPackagePath(importPath: string): boolean { + return importPath.startsWith("@"); +} + +/** + * Renders a Foundry (Solidity) test file that deploys all facets and + * creates a Diamond instance for testing. + * + * @param model - The test generation model with facet entries. + * @returns The complete Solidity test source code. + */ +export async function renderFoundryTest(model: TestGenerationModel): Promise { + const template = await loadTemplate("test", "foundry-test.sol"); + + const imports = model.facets + .map((facet) => { + const importPath = isPackagePath(facet.importPath) + ? facet.importPath + : `../${facet.importPath}`; + return `import {${facet.contractName}} from "${importPath}";`; + }) + .join("\n"); + + const baseFacets = model.facets.filter((facet) => facet.group === "base"); + const libraryFacets = model.facets.filter((facet) => facet.group === "library"); + let index = 0; + + const renderSetupLine = (facet: TestFacetEntry): string => { + const line = ` facets[${index}] = address(new ${facet.contractName}());`; + index += 1; + return line; + }; + + const baseLines = baseFacets.map(renderSetupLine).join("\n"); + const libraryLines = libraryFacets.map(renderSetupLine).join("\n"); + + return template + .replaceAll("{{IMPORTS}}", imports) + .replaceAll("{{FACET_COUNT}}", String(model.facetCount)) + .replaceAll("{{BASE_LINES}}", baseLines) + .replaceAll("{{LIBRARY_LINES}}", libraryLines); +} + +/** + * Renders a single facet deployment line using Hardhat + ethers.js. + * + * @param facet - The facet entry to deploy. + * @returns TypeScript code that deploys the facet and pushes its address. + */ +function renderHardhatEthersFacetDeploy(facet: TestFacetEntry): string { + const variableName = toCamelCase(facet.contractName) || "facet"; + return ` const ${variableName} = await ethers.deployContract("${facet.contractName}"); + await ${variableName}.waitForDeployment(); + facets.push(await ${variableName}.getAddress());`; +} + +/** + * Renders a single facet deployment line using Hardhat + viem. + * + * @param facet - The facet entry to deploy. + * @returns TypeScript code that deploys the facet and pushes its address. + */ +function renderHardhatViemFacetDeploy(facet: TestFacetEntry): string { + const variableName = toCamelCase(facet.contractName) || "facet"; + return ` const ${variableName} = await viem.deployContract("${facet.contractName}"); + facets.push(${variableName}.address);`; +} + +/** + * Renders base and library facet deploy sections for a Hardhat test file + * using the provided per-facet renderer. + * + * @param model - The test generation model with facet entries. + * @param renderFacetDeploy - Callback to render a single facet's deploy code. + * @returns An object with `baseLines` and `libraryLines` strings. + */ +function renderHardhatDeploySections( + model: TestGenerationModel, + renderFacetDeploy: (facet: TestFacetEntry) => string, +): { baseLines: string; libraryLines: string } { + const baseLines = model.facets + .filter((facet) => facet.group === "base") + .map(renderFacetDeploy) + .join("\n\n"); + const libraryLines = model.facets + .filter((facet) => facet.group === "library") + .map(renderFacetDeploy) + .join("\n\n"); + + return { baseLines, libraryLines }; +} + +/** + * Renders a complete Hardhat + ethers.js test file for the Diamond. + * + * @param model - The test generation model with facet entries. + * @returns The complete TypeScript test source code. + */ +export async function renderHardhatEthersTest(model: TestGenerationModel): Promise { + const [template, { baseLines, libraryLines }] = await Promise.all([ + loadTemplate("test", "hardhat-ethers-test.ts"), + renderHardhatDeploySections(model, renderHardhatEthersFacetDeploy), + ]); + + return template + .replaceAll("{{BASE_LINES}}", baseLines) + .replaceAll("{{LIBRARY_LINES}}", libraryLines) + .replaceAll("{{FACET_COUNT}}", String(model.facetCount)); +} + +/** + * Renders a complete Hardhat + viem test file for the Diamond. + * + * @param model - The test generation model with facet entries. + * @returns The complete TypeScript test source code. + */ +export async function renderHardhatViemTest(model: TestGenerationModel): Promise { + const [template, { baseLines, libraryLines }] = await Promise.all([ + loadTemplate("test", "hardhat-viem-test.ts"), + renderHardhatDeploySections(model, renderHardhatViemFacetDeploy), + ]); + + return template + .replaceAll("{{BASE_LINES}}", baseLines) + .replaceAll("{{LIBRARY_LINES}}", libraryLines) + .replaceAll("{{FACET_COUNT}}", String(model.facetCount)); +} diff --git a/cli/src/modules/testGeneration/types.ts b/cli/src/modules/testGeneration/types.ts new file mode 100644 index 00000000..702bb6d9 --- /dev/null +++ b/cli/src/modules/testGeneration/types.ts @@ -0,0 +1,14 @@ +import { DeployFacetGroup } from "../deployGeneration/types"; + +export type TestFacetEntry = { + facetName: string; + contractName: string; + importPath: string; + group: DeployFacetGroup; +}; + +export type TestGenerationModel = { + outputPath: string; + facets: TestFacetEntry[]; + facetCount: number; +}; diff --git a/cli/src/modules/validation/module.ts b/cli/src/modules/validation/module.ts new file mode 100644 index 00000000..b8564d66 --- /dev/null +++ b/cli/src/modules/validation/module.ts @@ -0,0 +1,217 @@ +import { ComposeContext } from "../../context/types"; +import { SelectorCollisionDeps } from "./types"; +import { + findIdentifierCollisions, + findSelectorCollisions, + findSelectorExportIssues, +} from "./validators"; +import { + getFacetScanResult, + getIdentifierCollisionValidationState, + getSelectorCollisionValidationState, + getSelectorExportValidationState, +} from "./state"; + +export { getFacetScanState, getSelectorExportValidationState, getSelectorCollisionValidationState, getIdentifierCollisionValidationState } from "./state"; + +/** + * Validates facet scans for selector export correctness and collision-free layouts. + * + * Provides three validation steps that run sequentially in the init pipelines: + * 1. Selector export validation — ensures every public/external function is declared in `exportSelectors()`. + * 2. Selector collision detection — detects duplicate 4-byte selectors across facets. + * 3. Identifier collision detection — detects incompatible storage layouts for the same storage slot. + * + * Each step stores its result as a `ModuleState` in `ctx.state` and sets + * `success: false` when issues are found. + */ +export const ValidationModule = { + /** + * Returns true when selector export validation has found blocking issues. + * + * Keeps validation state reads inside the validation module boundary. + */ + hasSelectorExportFailure(ctx: ComposeContext): boolean { + const state = getSelectorExportValidationState(ctx); + return Boolean(state && !state.success); + }, + + /** + * Returns true when selector collision validation has found blocking issues. + * + * Keeps validation state reads inside the validation module boundary. + */ + hasSelectorCollisionFailure(ctx: ComposeContext): boolean { + const state = getSelectorCollisionValidationState(ctx); + return Boolean(state && !state.success); + }, + + /** + * Returns true when identifier collision validation has found blocking issues. + * + * Keeps validation state reads inside the validation module boundary. + */ + hasIdentifierCollisionFailure(ctx: ComposeContext): boolean { + const state = getIdentifierCollisionValidationState(ctx); + return Boolean(state && !state.success); + }, + + /** + * Returns true when any validation stage has produced a blocking failure. + * + * Pipelines can use this for orchestration without importing validation helpers. + */ + hasBlockingFailure(ctx: ComposeContext): boolean { + return ( + ValidationModule.hasSelectorExportFailure(ctx) || + ValidationModule.hasSelectorCollisionFailure(ctx) || + ValidationModule.hasIdentifierCollisionFailure(ctx) + ); + }, + + /** + * Validates that every public/external function is exported by `exportSelectors()`. + * + * Requires `ctx.state.facetScan` to have been populated by + * {@link ScaffoldingModule.scanSelectedFacets}. For each facet, checks that + * every public/external function name appears in the facet's exported + * selector list and that no extra names are declared. + * + * @param ctx - The compose context with facet scan results. + * @returns The context with `ctx.state.validationSelectorExports` populated. + */ + async validateSelectorExports(ctx: ComposeContext): Promise { + const facetScan = getFacetScanResult(ctx); + + if (!facetScan) { + ctx.state.validationSelectorExports = { + success: false, + result: null, + error: { + code: "FACET_SCAN_MISSING", + message: "Facet scan must run before selector export validation.", + nativeError: null, + }, + }; + return ctx; + } + + const issues = findSelectorExportIssues(facetScan.facets); + const success = issues.length === 0; + + ctx.state.validationSelectorExports = { + success, + result: { + checkedFacets: facetScan.facetCount, + issues, + }, + error: success + ? null + : { + code: "SELECTOR_EXPORT_INVALID", + message: "One or more selected facets do not export all intended selectors.", + nativeError: null, + }, + }; + + return ctx; + }, + + /** + * Detects duplicate 4-byte selectors across selected exported facet functions. + * + * Uses the provided hashing adapter to compute 4-byte selectors, then groups + * facets by selector to find collisions. Requires `ctx.state.facetScan` to + * have been populated first. + * + * @param ctx - The compose context with facet scan results. + * @param deps - Dependencies: an `IHashingAdapter` for keccak256 computation. + * @returns The context with `ctx.state.validationSelectorCollisions` populated. + */ + async detectSelectorCollisions( + ctx: ComposeContext, + { hashing }: SelectorCollisionDeps, + ): Promise { + const facetScan = getFacetScanResult(ctx); + + if (!facetScan) { + ctx.state.validationSelectorCollisions = { + success: false, + result: null, + error: { + code: "FACET_SCAN_MISSING", + message: "Facet scan must run before selector collision detection.", + nativeError: null, + }, + }; + return ctx; + } + + const collisions = findSelectorCollisions(facetScan.facets, hashing); + const success = collisions.length === 0; + + ctx.state.validationSelectorCollisions = { + success, + result: { + checkedFacets: facetScan.facetCount, + collisions, + }, + error: success + ? null + : { + code: "SELECTOR_COLLISION_DETECTED", + message: "Two or more selected facets export the same function selector.", + nativeError: null, + }, + }; + + return ctx; + }, + + /** + * Detects incompatible storage layouts sharing the same storage identifier. + * + * Groups storage layouts by slot identifier and checks whether all layouts + * for a given slot are prefix-compatible (safe extensions). Requires + * `ctx.state.facetScan` to have been populated first. + * + * @param ctx - The compose context with facet scan results. + * @returns The context with `ctx.state.validationIdentifierCollisions` populated. + */ + async detectIdentifierCollisions(ctx: ComposeContext): Promise { + const facetScan = getFacetScanResult(ctx); + + if (!facetScan) { + ctx.state.validationIdentifierCollisions = { + success: false, + result: null, + error: { + code: "FACET_SCAN_MISSING", + message: "Facet scan must run before identifier collision detection.", + nativeError: null, + }, + }; + return ctx; + } + + const collisions = findIdentifierCollisions(facetScan.facets); + const success = collisions.length === 0; + + ctx.state.validationIdentifierCollisions = { + success, + result: { + checkedFacets: facetScan.facetCount, + collisions, + }, + error: success + ? null + : { + code: "IDENTIFIER_COLLISION_DETECTED", + message: "Two or more selected facets use incompatible storage layouts for the same identifier.", + nativeError: null, + }, + }; + + return ctx; + }, +}; diff --git a/cli/src/modules/validation/state.ts b/cli/src/modules/validation/state.ts new file mode 100644 index 00000000..3962a2f0 --- /dev/null +++ b/cli/src/modules/validation/state.ts @@ -0,0 +1,69 @@ +import { ComposeContext, ModuleState } from "../../context/types"; +import { + FacetScanStateResult, + FacetScanResultCollection, + SelectorExportValidationResult, + SelectorCollisionValidationResult, + IdentifierCollisionValidationResult, +} from "./types"; + +/** + * Extracts the facet scan result from the compose context state. + * + * @param ctx - The compose context with facet scan state. + * @returns The facet scan result, or null if not yet populated. + */ +export function getFacetScanResult(ctx: ComposeContext): FacetScanStateResult | null { + const state = ctx.state.facetScan as ModuleState | undefined; + return state?.result ?? null; +} + +/** + * Returns the full facet scan module state from the compose context. + * + * @param ctx - The compose context. + * @returns The facet scan module state, or null if not yet populated. + */ +export function getFacetScanState(ctx: ComposeContext): ModuleState | null { + return (ctx.state.facetScan as ModuleState | undefined) ?? null; +} + +/** + * Returns the selector export validation module state from the compose context. + * + * @param ctx - The compose context. + * @returns The validation state, or null if not yet populated. + */ +export function getSelectorExportValidationState( + ctx: ComposeContext, +): ModuleState | null { + return (ctx.state.validationSelectorExports as ModuleState | undefined) ?? null; +} + +/** + * Returns the selector collision validation module state from the compose context. + * + * @param ctx - The compose context. + * @returns The validation state, or null if not yet populated. + */ +export function getSelectorCollisionValidationState( + ctx: ComposeContext, +): ModuleState | null { + return ( + ctx.state.validationSelectorCollisions as ModuleState | undefined + ) ?? null; +} + +/** + * Returns the identifier collision validation module state from the compose context. + * + * @param ctx - The compose context. + * @returns The validation state, or null if not yet populated. + */ +export function getIdentifierCollisionValidationState( + ctx: ComposeContext, +): ModuleState | null { + return ( + ctx.state.validationIdentifierCollisions as ModuleState | undefined + ) ?? null; +} diff --git a/cli/src/modules/validation/types.ts b/cli/src/modules/validation/types.ts new file mode 100644 index 00000000..673a6e8a --- /dev/null +++ b/cli/src/modules/validation/types.ts @@ -0,0 +1,91 @@ +import { IHashingAdapter } from "../../adapters/interface/IHashingAdapter"; + +export type FunctionInfo = { + name: string; + signature: string; + visibility: "external" | "public"; +}; + +export type FacetScanResult = { + facetName: string; + path: string; + functions: FunctionInfo[]; + exportedSelectors: string[]; + missingExports: string[]; + extraExports: string[]; + storageLayouts: StorageLayoutInfo[]; +}; + +export type FacetScanResultCollection = { + facets: FacetScanWarning[]; +}; + +export type FacetScanStateResult = { + facets: FacetScanResult[]; + facetCount: number; +}; + +export type SelectorExportIssue = { + facetName: string; + path: string; + missingExports: string[]; + extraExports: string[]; +}; + +export type SelectorOwner = { + facetName: string; + path: string; + functionName: string; + signature: string; +}; + +export type SelectorCollision = { + selector: string; + owners: SelectorOwner[]; +}; + +export type SelectorCollisionDeps = { + hashing: IHashingAdapter; +}; + +export type StorageLayoutInfo = { + slot: string; + layout: string[]; + source: "erc8042" | "slot-assignment"; + structName: string | null; +}; + +export type IdentifierCollisionOwner = { + facetName: string; + path: string; + slot: string; + layout: string[]; + source: StorageLayoutInfo["source"]; + structName: string | null; +}; + +export type IdentifierCollision = { + identifier: string; + owners: IdentifierCollisionOwner[]; +}; + +export type SelectorExportValidationResult = { + checkedFacets: number; + issues: SelectorExportIssue[]; +}; + +export type SelectorCollisionValidationResult = { + checkedFacets: number; + collisions: SelectorCollision[]; +}; + +export type IdentifierCollisionValidationResult = { + checkedFacets: number; + collisions: IdentifierCollision[]; +}; + +export type FacetScanWarning = { + facetName: string; + path: string; + warnings: string[]; +}; diff --git a/cli/src/modules/validation/validators.ts b/cli/src/modules/validation/validators.ts new file mode 100644 index 00000000..2a96659f --- /dev/null +++ b/cli/src/modules/validation/validators.ts @@ -0,0 +1,118 @@ +import { IHashingAdapter } from "../../adapters/interface/IHashingAdapter"; +import { isArrayPrefix } from "../../utils/arrays"; +import { + FacetScanResult, + SelectorExportIssue, + SelectorCollision, + SelectorOwner, + IdentifierCollision, + IdentifierCollisionOwner, +} from "./types"; + +/** + * Finds facets with missing or extra exported selectors compared to their functions. + * + * @param facets - Array of scanned facet results. + * @returns Array of selector export issues (only facets with problems). + */ +export function findSelectorExportIssues(facets: FacetScanResult[]): SelectorExportIssue[] { + return facets + .map((facet) => ({ + facetName: facet.facetName, + path: facet.path, + missingExports: facet.missingExports, + extraExports: facet.extraExports, + })) + .filter((issue) => issue.missingExports.length > 0 || issue.extraExports.length > 0); +} + +/** + * Detects duplicate 4-byte selectors across different facets. + * Groups functions by their keccak256-derived selector and returns collisions + * where the same selector appears in more than one facet. + * + * @param facets - Array of scanned facet results. + * @param hashing - Hashing adapter for keccak256 computation. + * @returns Array of selector collisions across facets. + */ +export function findSelectorCollisions( + facets: FacetScanResult[], + hashing: IHashingAdapter, +): SelectorCollision[] { + const ownersBySelector = new Map(); + + for (const facet of facets) { + const functionsBySignature = new Map(facet.functions.map((fn) => [fn.signature, fn])); + + for (const exportedSignature of facet.exportedSelectors) { + const fn = functionsBySignature.get(exportedSignature); + if (!fn) { + continue; + } + + const selector = hashing.keccak256(fn.signature).slice(0, 10); + const owners = ownersBySelector.get(selector) ?? []; + owners.push({ + facetName: facet.facetName, + path: facet.path, + functionName: fn.name, + signature: fn.signature, + }); + ownersBySelector.set(selector, owners); + } + } + + return [...ownersBySelector.entries()] + .map(([selector, owners]) => ({ selector, owners })) + .filter((collision) => new Set(collision.owners.map((owner) => owner.facetName)).size > 1); +} + +/** + * Detects incompatible storage layouts sharing the same storage slot identifier. + * Layouts are compatible if they are prefix extensions of the shortest layout. + * + * @param facets - Array of scanned facet results. + * @returns Array of identifier collisions with incompatible layouts. + */ +export function findIdentifierCollisions(facets: FacetScanResult[]): IdentifierCollision[] { + const ownersByIdentifier = new Map(); + + for (const facet of facets) { + for (const storageLayout of facet.storageLayouts) { + const identifier = storageLayout.slot; + const owners = ownersByIdentifier.get(identifier) ?? []; + owners.push({ + facetName: facet.facetName, + path: facet.path, + slot: storageLayout.slot, + layout: storageLayout.layout, + source: storageLayout.source, + structName: storageLayout.structName, + }); + ownersByIdentifier.set(identifier, owners); + } + } + + return [...ownersByIdentifier.entries()] + .filter(([, owners]) => owners.length > 1) + .filter(([, owners]) => !areLayoutsPrefixCompatible(owners.map((owner) => owner.layout))) + .map(([identifier, owners]) => ({ identifier, owners })); +} + +/** + * Checks whether all layouts are prefix-compatible with the shortest layout. + * A layout is prefix-compatible if all others extend it without conflicts. + * + * @param layouts - Array of layout arrays to check. + * @returns True if all layouts are prefix-compatible. + */ +function areLayoutsPrefixCompatible(layouts: string[][]): boolean { + if (layouts.length <= 1) { + return true; + } + + const sorted = [...layouts].sort((a, b) => a.length - b.length); + const shortest = sorted[0]; + + return sorted.every((layout) => isArrayPrefix(shortest, layout)); +} diff --git a/cli/src/pipelines/entryPipeline.ts b/cli/src/pipelines/entryPipeline.ts new file mode 100644 index 00000000..78341ca2 --- /dev/null +++ b/cli/src/pipelines/entryPipeline.ts @@ -0,0 +1,17 @@ +import { ComposeContext } from "../context/types"; +import { PipelineBuilderModule } from "../modules/pipelineBuilder/module"; + +/** + * Entrypoint Pipeline. + * + * Routes the parsed command to the appropriate pipeline. + */ +export const EntryPipeline = { + async execute(ctx: ComposeContext): Promise { + if (!ctx.param.command) { + return ctx; + } + ctx = await PipelineBuilderModule.route(ctx); + return ctx; + }, +}; diff --git a/cli/src/pipelines/infoPipeline.ts b/cli/src/pipelines/infoPipeline.ts new file mode 100644 index 00000000..b658bc4d --- /dev/null +++ b/cli/src/pipelines/infoPipeline.ts @@ -0,0 +1,14 @@ +import { ComposeContext } from "../context/types"; +import { InfoModule } from "../modules/info/module"; + +/** + * Info Pipeline. + * + * Loads compose.json, scans facets for selectors and storage layouts, + * and displays a summary of the local project. + */ +export const InfoPipeline = { + async execute(ctx: ComposeContext): Promise { + return InfoModule.displayProjectInfo(ctx); + }, +}; diff --git a/cli/src/pipelines/initPipeline.ts b/cli/src/pipelines/initPipeline.ts new file mode 100644 index 00000000..dc0776a6 --- /dev/null +++ b/cli/src/pipelines/initPipeline.ts @@ -0,0 +1,131 @@ +import { ComposeContext } from "../context/types"; +import { ConfigModule } from "../modules/config/module"; +import { TerminalOutputModule } from "../modules/terminalOutput/module"; +import { InitModule } from "../modules/init/module"; +import { PreflightModule } from "../modules/preflight/module"; +import { ProjectDirModule } from "../modules/projectDir/module"; +import { ScaffoldingModule } from "../modules/scaffolding/module"; +import { DiamondGenerationModule } from "../modules/diamondGeneration/module"; +import { DeployGenerationModule } from "../modules/deployGeneration/module"; +import { TestGenerationModule } from "../modules/testGeneration/module"; +import { ValidationModule } from "../modules/validation/module"; +import { DependencyKey } from "../resolver/dependencyKey"; +import { DependencyResolver } from "../resolver/dependencyResolver"; +import { IFrameworkAdapter } from "../adapters/interface/IFrameworkAdapter"; +import { getDiamondCompilerVersion } from "../modules/config/module"; +import { BasesCatalog } from "../modules/config/types"; + +/** + * Init Pipeline. + * + * Orchestrates the full `init` command flow: + * catalog load → preflight checks → input collection (interactive or --yes) → + * project directory setup → facet validation → scaffolding → compose.json write → + * validation report → success output + */ +export const InitPipeline = { + /** + * Execute the init flow end-to-end. + * @param ctx Execution context with parsed CLI flags + * @returns Context with init results or validation errors + */ + async execute(ctx: ComposeContext): Promise { + TerminalOutputModule.showComposeHeader(); + + ctx = await ConfigModule.loadBasesCatalog(ctx); + + ctx = ctx.param.yes + ? await InitModule.runInitNonInteractive(ctx) + : await InitModule.runInitInteractive(ctx); + + ctx = await PreflightModule.check(ctx); + + ctx = await ProjectDirModule.resolve(ctx); + ctx = await ProjectDirModule.validate(ctx); + + const framework = String(ctx.param.framework ?? "foundry"); + + const deps = await DependencyResolver.resolve([ + { key: DependencyKey.Hashing }, + { key: framework as DependencyKey }, + ]); + + if (!deps.hashing) { + throw new Error("Hashing dependency was not resolved."); + } + + const adapter = deps[framework as DependencyKey] as IFrameworkAdapter | undefined; + if (!adapter) { + throw new Error(`${framework} adapter was not resolved.`); + } + + const root = String(ctx.param.projectRoot ?? ""); + const contractSourceRoot = adapter.getContractSourceRoot(root); + const compilerVersion = getDiamondCompilerVersion(ctx.config.bases as BasesCatalog); + const projectName = String(ctx.param.projectName ?? "my-diamond"); + const installDeps = ctx.param.installDeps !== false; + + await adapter.initProject(ctx); + const scaffoldMapEntries = await ScaffoldingModule.copyFacets(ctx, contractSourceRoot); + await adapter.writeConfig(ctx, { compilerVersion, projectName, installDeps }); + ctx = ScaffoldingModule.recordScaffoldMap(ctx, scaffoldMapEntries); + + ctx = await ScaffoldingModule.scanSelectedFacets(ctx, adapter); + ctx = await ValidationModule.validateSelectorExports(ctx); + + if (ValidationModule.hasSelectorExportFailure(ctx)) { + ctx = await TerminalOutputModule.showReport(ctx); + return ctx; + } + + ctx = await ValidationModule.detectSelectorCollisions(ctx, { + hashing: deps.hashing, + }); + + if (ValidationModule.hasSelectorCollisionFailure(ctx)) { + ctx = await TerminalOutputModule.showReport(ctx); + return ctx; + } + + ctx = await ValidationModule.detectIdentifierCollisions(ctx); + + if (ValidationModule.hasIdentifierCollisionFailure(ctx)) { + ctx = await TerminalOutputModule.showReport(ctx); + return ctx; + } + + ctx = await DiamondGenerationModule.generateDiamondContract(ctx, contractSourceRoot); + ctx = await DeployGenerationModule.generateDeployScript( + ctx, + adapter.getScriptRoot(root), + ); + ctx = await TestGenerationModule.generateTestFile( + ctx, + adapter.getTestRoot(root), + ); + ctx = ScaffoldingModule.buildComposeJson(ctx, contractSourceRoot); + ctx = await ScaffoldingModule.validateLocalFacetFiles(ctx); + ctx = await ScaffoldingModule.writeComposeConfig(ctx); + + ctx.state.initPipeline = { + success: true, + result: { + message: `${framework.charAt(0).toUpperCase() + framework.slice(1)} demo project generated.`, + projectRoot: ctx.param.projectRoot, + }, + error: null, + }; + + ctx = await TerminalOutputModule.showReport(ctx); + + if (ValidationModule.hasBlockingFailure(ctx)) { + return ctx; + } + + if (ctx.state.initPipeline?.success) { + TerminalOutputModule.showSuccess(ctx); + } + + return ctx; + }, +}; diff --git a/cli/src/prompts/initPrompts.js b/cli/src/prompts/initPrompts.js deleted file mode 100644 index 9f1661a7..00000000 --- a/cli/src/prompts/initPrompts.js +++ /dev/null @@ -1,68 +0,0 @@ -const inquirer = require("inquirer").default; -const { getTemplateChoices, validateProjectLocation } = require("../utils/prompts/initUtils"); - -async function askInitPrompts(seed = {}) { - const answers = await inquirer.prompt([ - { - type: "input", - name: "name", - message: 'Where would you like to initialize the project? ("." for current directory) ', - default: seed.name || "my-first-diamond", - when: () => !seed.name, - validate: validateProjectLocation, - }, - { - type: "select", - name: "template", - message: "Choose your diamond template? ", - choices: () => getTemplateChoices(), - when: () => !seed.template, - }, - { - type: "select", - name: "framework", - message: "Choose your framework?", - choices: ["foundry", "hardhat"], - when: () => !seed.framework, - }, - { - type: "select", - name: "hardhatProjectType", - message: "What Hardhat 3 project do you want to create? ", - choices: [ - { - name: "Minimal Hardhat Project", - value: "minimal", - }, - { - name: "TypeScript Hardhat project using Mocha and Ethers.js", - value: "mocha-ethers", - }, - { - name: "TypeScript Hardhat project using Node Test Runner and Viem", - value: "node-runner-viem", - }, - ], - when: (answers) => { - const framework = seed.framework || answers.framework; - return framework === "hardhat" && !seed.hardhatProjectType; - }, - }, - { - type: "confirm", - name: "installDeps", - message: "Install dependencies now? ", - default: true, - when: () => typeof seed.installDeps !== "boolean", - }, - ]); - - return { - ...seed, - ...answers, - }; -} - -module.exports = { - askInitPrompts -}; diff --git a/cli/src/resolver/dependencyKey.ts b/cli/src/resolver/dependencyKey.ts new file mode 100644 index 00000000..804380ad --- /dev/null +++ b/cli/src/resolver/dependencyKey.ts @@ -0,0 +1,11 @@ +/** + * Type-safe keys for resolver dependencies. + * + * Each key maps to a specific adapter factory in the {@link DependencyRegistry} + * and a typed result in the {@link DependencyMap}. + */ +export enum DependencyKey { + Hashing = "hashing", + Foundry = "foundry", + Hardhat = "hardhat", +} diff --git a/cli/src/resolver/dependencyRegistry.ts b/cli/src/resolver/dependencyRegistry.ts new file mode 100644 index 00000000..2fa85052 --- /dev/null +++ b/cli/src/resolver/dependencyRegistry.ts @@ -0,0 +1,41 @@ +import { + HashingAdapter, +} from "../adapters/hashingAdapter"; +import { IHashingAdapter } from "../adapters/interface/IHashingAdapter"; +import { IFrameworkAdapter } from "../adapters/interface/IFrameworkAdapter"; +import { foundryAdapter } from "../adapters/foundryAdapter"; +import { hardhatAdapter } from "../adapters/hardhatAdapter"; +import { DependencyKey } from "./dependencyKey"; + +/** Optional parameters passed to a dependency factory. */ +export type DependencyParams = Record; + +/** Factory function that creates or returns a dependency instance. */ +export type DependencyFactory = ( + params?: DependencyParams, +) => Promise | T; + +/** Typed map of all dependency keys to their resolved adapter types. */ +export type DependencyMap = { + [DependencyKey.Hashing]: IHashingAdapter; + [DependencyKey.Foundry]: IFrameworkAdapter; + [DependencyKey.Hardhat]: IFrameworkAdapter; +}; + +/** + * Maps dependency keys to adapter factories. + * + * The registry is the single source of truth for which adapters are available + * and how they are instantiated. Each entry is a factory function that returns + * the corresponding adapter singleton or creates a new instance. + * + * Used by {@link DependencyResolver} to look up and invoke factories for + * requested dependency keys. + */ +export const DependencyRegistry: { + [Key in DependencyKey]: DependencyFactory; +} = { + [DependencyKey.Hashing]: () => HashingAdapter, + [DependencyKey.Foundry]: () => foundryAdapter, + [DependencyKey.Hardhat]: () => hardhatAdapter, +}; diff --git a/cli/src/resolver/dependencyResolver.ts b/cli/src/resolver/dependencyResolver.ts new file mode 100644 index 00000000..877060ab --- /dev/null +++ b/cli/src/resolver/dependencyResolver.ts @@ -0,0 +1,49 @@ +import { + DependencyMap, + DependencyParams, + DependencyRegistry, +} from "./dependencyRegistry"; +import { DependencyKey } from "./dependencyKey"; + +/** A request for a specific dependency, optionally with parameters. */ +export type DependencyRequest = { + key: DependencyKey; + params?: DependencyParams; +}; + +/** + * Resolves adapter dependencies requested by pipelines. + * + * Accepts an array of {@link DependencyRequest} objects, looks up each key in + * the {@link DependencyRegistry}, invokes the factory, and collects the results + * into a partial {@link DependencyMap}. + */ +export const DependencyResolver = { + /** + * Resolves the requested adapter dependencies from the registry. + * + * Iterates over each request, retrieves the factory from the registry, and + * invokes it (passing optional params). Throws if a factory is not found for + * a given key. + * + * @param requests - Array of dependency requests specifying which adapters to resolve. + * @returns A partial map of resolved dependencies keyed by {@link DependencyKey}. + */ + async resolve( + requests: DependencyRequest[], + ): Promise> { + const deps: Partial = {}; + + for (const request of requests) { + const factory = DependencyRegistry[request.key]; + + if (!factory) { + throw new Error(`Dependency factory not found: ${request.key}`); + } + + deps[request.key] = await factory(request.params) as any; + } + + return deps; + }, +}; diff --git a/cli/src/scaffold/frameworks/foundry.js b/cli/src/scaffold/frameworks/foundry.js deleted file mode 100644 index db4c778b..00000000 --- a/cli/src/scaffold/frameworks/foundry.js +++ /dev/null @@ -1,46 +0,0 @@ -const fs = require("fs-extra"); -const path = require("path"); -const { copyTemplate, getTemplateDisplayName } = require("../utils/fileManager"); -const { runCommand } = require("../../utils/exec"); -const { logger } = require("../../utils/logger"); -const { COMPOSE_FOUNDRY_DEP } = require("../../config/constants"); - -async function scaffoldFoundry(projectName, templatePath, projectDir, options) { - const shouldInstallDeps = Boolean(options.installDeps); - - logger.info(`Scaffolding Foundry project in "${projectDir}"…`); - - await fs.ensureDir(projectDir); - - await runCommand("forge", ["init", "."], { cwd: projectDir }); - - if (shouldInstallDeps) { - logger.info("Installing Compose dependencies with forge…"); - await runCommand("forge", ["install", COMPOSE_FOUNDRY_DEP], { cwd: projectDir }); - } else { - logger.info("Skipping dependency installation... "); - } - - // Remove default Forge starter contracts/scripts/tests for replacement with our template. - await Promise.all([ - fs.remove(path.join(projectDir, "src")), - fs.remove(path.join(projectDir, "test")), - fs.remove(path.join(projectDir, "script")), - ]); - - const templateName = getTemplateDisplayName(templatePath); - logger.info(`Applying template "${templateName}"`); - - await copyTemplate(templatePath, projectDir); - - const nextSteps = shouldInstallDeps - ? ["forge build && forge test"] - : [`forge install ${COMPOSE_FOUNDRY_DEP}`, "forge build && forge test"]; - - return { nextSteps }; -} - -module.exports = { - scaffoldFoundry, -}; - diff --git a/cli/src/scaffold/frameworks/hardhat.js b/cli/src/scaffold/frameworks/hardhat.js deleted file mode 100644 index 348387f2..00000000 --- a/cli/src/scaffold/frameworks/hardhat.js +++ /dev/null @@ -1,50 +0,0 @@ -const fs = require("fs-extra"); -const path = require("node:path"); -const { copyTemplate, readJson, writeJson } = require("../utils/fileManager"); -const { orderPackageJsonWithDepsBeforeDevDeps } = require("../utils/packageOrderer"); -const { runCommand } = require("../../utils/exec"); -const { logger } = require("../../utils/logger"); -const { COMPOSE_NPM_PACKAGE, COMPOSE_NPM_VERSION } = require("../../config/constants"); - -async function scaffoldHardhat(projectName, templatePath, projectDir, options) { - await fs.ensureDir(projectDir); - await copyTemplate(templatePath, projectDir); - - const shouldInstallDeps = Boolean(options.installDeps); - - const packageJsonPath = path.join(projectDir, "package.json"); - const packageJson = await readJson(packageJsonPath); - - packageJson.name = projectName; - packageJson.type = "module"; - - packageJson.scripts = packageJson.scripts || {}; - packageJson.scripts.build = "npx hardhat compile"; - packageJson.scripts.test = "npx hardhat test"; - - packageJson.devDependencies = packageJson.devDependencies || {}; - - packageJson.dependencies = packageJson.dependencies || {}; - packageJson.dependencies[COMPOSE_NPM_PACKAGE] = COMPOSE_NPM_VERSION; - - const orderedPackageJson = orderPackageJsonWithDepsBeforeDevDeps(packageJson); - await writeJson(packageJsonPath, orderedPackageJson); - - if (shouldInstallDeps) { - logger.info("Installing project dependencies…"); - await runCommand("npm", ["install"], { cwd: projectDir }); - } else { - logger.info("Skipping dependency installation (installDeps=false)."); - } - - const nextSteps = shouldInstallDeps - ? ["npx hardhat compile && npx hardhat test"] - : ["npm install", "npx hardhat compile && npx hardhat test"]; - - return { nextSteps }; -} - -module.exports = { - scaffoldHardhat, -}; - diff --git a/cli/src/scaffold/scaffold.js b/cli/src/scaffold/scaffold.js deleted file mode 100644 index 2e75e0f5..00000000 --- a/cli/src/scaffold/scaffold.js +++ /dev/null @@ -1,49 +0,0 @@ -const fs = require("fs-extra"); -const { - assertTargetDoesNotExist, - assertDirectoryEmpty, - resolveProjectDir, - getProjectDisplayName, -} = require("./utils/fileManager"); -const { replaceTokensRecursively } = require("./utils/tokenReplace"); -const { scaffoldFoundry } = require("./frameworks/foundry"); -const { scaffoldHardhat } = require("./frameworks/hardhat"); - -async function scaffold({ projectName, templatePath, options }) { - const projectDir = resolveProjectDir(projectName); - if (projectName === ".") { - await assertDirectoryEmpty(projectDir); - } else { - await assertTargetDoesNotExist(projectDir); - } - - const displayName = getProjectDisplayName(projectName, projectDir); - - const templateExists = await fs.pathExists(templatePath); - if (!templateExists) { - throw new Error(`Template path does not exist: ${templatePath}`); - } - - let frameworkResult; - if (options.framework === "foundry") { - frameworkResult = await scaffoldFoundry(displayName, templatePath, projectDir, options); - } else if (options.framework === "hardhat") { - frameworkResult = await scaffoldHardhat(displayName, templatePath, projectDir, options); - } else { - throw new Error(`Unknown framework: ${options.framework}`); - } - - await replaceTokensRecursively(projectDir, { - "{{projectName}}": displayName, - }); - - return { - projectDir, - displayName, - nextSteps: frameworkResult?.nextSteps || [], - }; -} - -module.exports = { - scaffold, -}; diff --git a/cli/src/scaffold/utils/fileManager.js b/cli/src/scaffold/utils/fileManager.js deleted file mode 100644 index cb90bced..00000000 --- a/cli/src/scaffold/utils/fileManager.js +++ /dev/null @@ -1,75 +0,0 @@ -const fs = require("fs-extra"); -const path = require("node:path"); - -async function assertTargetDoesNotExist(projectDir) { - const exists = await fs.pathExists(projectDir); - if (exists) { - throw new Error(`Target directory already exists: ${projectDir}`); - } -} - -async function copyTemplate(templateDir, projectDir) { - await fs.copy(templateDir, projectDir); -} - -async function readJson(filePath) { - return fs.readJson(filePath); -} - -async function writeJson(filePath, data) { - await fs.writeJson(filePath, data, { spaces: 2 }); -} - -async function appendLineIfMissing(filePath, line) { - const exists = await fs.pathExists(filePath); - if (!exists) { - await fs.outputFile(filePath, `${line}\n`); - return; - } - - const content = await fs.readFile(filePath, "utf8"); - if (!content.includes(line)) { - await fs.writeFile(filePath, `${content.trimEnd()}\n${line}\n`); - } -} - -async function assertDirectoryEmpty(projectDir) { - const entries = await fs.readdir(projectDir); - const ignoredEntries = [".git"]; - const nonIgnored = entries.filter((entry) => !ignoredEntries.includes(entry)); - if (nonIgnored.length > 0) { - throw new Error(`Target directory is not empty: ${projectDir}`); - } -} - -function resolveProjectDir(projectName) { - return path.join(process.cwd(), projectName); -} - -function getProjectDisplayName(projectName, projectDir) { - if (projectName === ".") { - return path.basename(projectDir); - } - return projectName; -} - -function getTemplateDisplayName(templatePath) { - const templatesRoot = path.join(__dirname, "..", "..", "templates"); - let templateName = path.relative(templatesRoot, templatePath).replace(/\\/g, "/"); - if (templateName.startsWith("..")) { - templateName = path.basename(templatePath); - } - return templateName; -} - -module.exports = { - assertTargetDoesNotExist, - assertDirectoryEmpty, - copyTemplate, - readJson, - writeJson, - appendLineIfMissing, - resolveProjectDir, - getProjectDisplayName, - getTemplateDisplayName, -}; diff --git a/cli/src/scaffold/utils/packageOrderer.js b/cli/src/scaffold/utils/packageOrderer.js deleted file mode 100644 index 26711440..00000000 --- a/cli/src/scaffold/utils/packageOrderer.js +++ /dev/null @@ -1,32 +0,0 @@ -function orderPackageJsonWithDepsBeforeDevDeps(packageJson) { - const orderedPackageJson = {}; - const dependencies = packageJson.dependencies || {}; - const devDependencies = packageJson.devDependencies || {}; - let insertedDependencyBlocks = false; - - for (const [key, value] of Object.entries(packageJson)) { - if (key === "dependencies") { - continue; - } - - if (key === "devDependencies") { - orderedPackageJson.dependencies = dependencies; - orderedPackageJson.devDependencies = devDependencies; - insertedDependencyBlocks = true; - continue; - } - - orderedPackageJson[key] = value; - } - - if (!insertedDependencyBlocks) { - orderedPackageJson.dependencies = dependencies; - orderedPackageJson.devDependencies = devDependencies; - } - - return orderedPackageJson; -} - -module.exports = { - orderPackageJsonWithDepsBeforeDevDeps, -}; diff --git a/cli/src/scaffold/utils/templateLoader.js b/cli/src/scaffold/utils/templateLoader.js deleted file mode 100644 index 540c3309..00000000 --- a/cli/src/scaffold/utils/templateLoader.js +++ /dev/null @@ -1,51 +0,0 @@ -const path = require("node:path"); -const fs = require("fs-extra"); -const { TEMPLATE_REGISTRY_PATH } = require("../../config/constants"); -const { validateTemplatesConfig } = require("../../config/validateTemplatesConfig"); - -async function loadTemplateConfig() { - const config = await fs.readJson(TEMPLATE_REGISTRY_PATH); - validateTemplatesConfig(config); - return config; -} - -function pickVariant(config, options) { - const { template = config.defaultTemplateId, framework, language, projectType } = options; - - const templateEntry = config.templates.find((item) => item.id === template); - if (!templateEntry) { - throw new Error(`Template not found: ${template}`); - } - - const variant = templateEntry.variants.find((item) => { - if (framework && item.framework !== framework) { - return false; - } - if (item.framework === "hardhat" && language && item.language !== language) { - return false; - } - if (projectType && item.projectType && item.projectType !== projectType) { - return false; - } - if (!framework && item.id === config.defaultTemplateId) { - return true; - } - return framework ? true : false; - }); - - if (!variant) { - throw new Error(`No template variant for template=${template}, framework=${framework}, language=${language || "-"}`); - } - - return variant; -} - -function resolveTemplatePath(variant) { - return path.join(__dirname, "..", "..", variant.path); -} - -module.exports = { - loadTemplateConfig, - pickVariant, - resolveTemplatePath, -}; diff --git a/cli/src/scaffold/utils/tokenReplace.js b/cli/src/scaffold/utils/tokenReplace.js deleted file mode 100644 index 1b39ad1e..00000000 --- a/cli/src/scaffold/utils/tokenReplace.js +++ /dev/null @@ -1,40 +0,0 @@ -const fs = require("fs-extra"); -const path = require("node:path"); - -async function replaceTokensInFile(filePath, tokenMap) { - const content = await fs.readFile(filePath, "utf8"); - let updated = content; - - Object.entries(tokenMap).forEach(([token, value]) => { - updated = updated.split(token).join(value); - }); - - if (updated !== content) { - await fs.writeFile(filePath, updated); - } -} - -async function replaceTokensRecursively(rootDir, tokenMap) { - const entries = await fs.readdir(rootDir); - - await Promise.all( - entries.map(async (entry) => { - const fullPath = path.join(rootDir, entry); - const stat = await fs.stat(fullPath); - - if (stat.isDirectory()) { - await replaceTokensRecursively(fullPath, tokenMap); - return; - } - - const textExtensions = [".md", ".txt", ".json", ".toml", ".js", ".ts", ".sol"]; - if (textExtensions.some((ext) => fullPath.endsWith(ext))) { - await replaceTokensInFile(fullPath, tokenMap); - } - }) - ); -} - -module.exports = { - replaceTokensRecursively, -}; diff --git a/cli/src/templates/counter/CounterDataFacet.sol b/cli/src/templates/counter/CounterDataFacet.sol new file mode 100644 index 00000000..037e87ea --- /dev/null +++ b/cli/src/templates/counter/CounterDataFacet.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +contract CounterDataFacet { + bytes32 constant STORAGE_POSITION = keccak256("counter"); + + /** + * @custom:storage-location erc8042:counter + */ + struct CounterStorage { + uint256 count; + } + + function getStorage() internal pure returns (CounterStorage storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function getCount() external view returns (uint256) { + return getStorage().count; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.getCount.selector); + } +} diff --git a/cli/src/templates/counter/CounterDecrementFacet.sol b/cli/src/templates/counter/CounterDecrementFacet.sol new file mode 100644 index 00000000..de7814b5 --- /dev/null +++ b/cli/src/templates/counter/CounterDecrementFacet.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +contract CounterDecrementFacet { + bytes32 constant STORAGE_POSITION = keccak256("counter"); + + /** + * @custom:storage-location erc8042:counter + */ + struct CounterStorage { + uint256 count; + } + + function getStorage() internal pure returns (CounterStorage storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function decrement() external { + require(getStorage().count > 0, "Counter: underflow"); + getStorage().count--; + } + + function decrementBy(uint256 _amount) external { + require(getStorage().count >= _amount, "Counter: underflow"); + getStorage().count -= _amount; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.decrement.selector, this.decrementBy.selector); + } +} diff --git a/cli/src/templates/counter/CounterIncrementFacet.sol b/cli/src/templates/counter/CounterIncrementFacet.sol new file mode 100644 index 00000000..d63070c2 --- /dev/null +++ b/cli/src/templates/counter/CounterIncrementFacet.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ +contract CounterIncrementFacet { + bytes32 constant STORAGE_POSITION = keccak256("counter"); + + /** + * @custom:storage-location erc8042:counter + */ + struct CounterStorage { + uint256 count; + } + + function getStorage() internal pure returns (CounterStorage storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function increment() external { + getStorage().count++; + } + + function incrementBy(uint256 _amount) external { + getStorage().count += _amount; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.increment.selector, this.incrementBy.selector); + } +} diff --git a/cli/src/templates/counter/CounterResetFacet.sol b/cli/src/templates/counter/CounterResetFacet.sol new file mode 100644 index 00000000..ca67e419 --- /dev/null +++ b/cli/src/templates/counter/CounterResetFacet.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +/// @custom:storage-location erc7201:counter +contract CounterResetFacet { + bytes32 constant STORAGE_POSITION = keccak256("counter"); + + /** + * @custom:storage-location erc8042:counter + */ + struct CounterStorage { + uint256 count; + } + + function getStorage() internal pure returns (CounterStorage storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function reset() external { + getStorage().count = 0; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.reset.selector); + } +} diff --git a/cli/src/templates/counter/CounterSetFacet.sol b/cli/src/templates/counter/CounterSetFacet.sol new file mode 100644 index 00000000..8db9ab80 --- /dev/null +++ b/cli/src/templates/counter/CounterSetFacet.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +contract CounterSetFacet { + bytes32 constant STORAGE_POSITION = keccak256("counter"); + + /** + * @custom:storage-location erc8042:counter + */ + struct CounterStorage { + uint256 count; + } + + function getStorage() internal pure returns (CounterStorage storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function set(uint256 _value) external { + getStorage().count = _value; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.set.selector); + } +} diff --git a/cli/src/templates/default/foundry/.gitignore b/cli/src/templates/default/foundry/.gitignore deleted file mode 100644 index c8ba071a..00000000 --- a/cli/src/templates/default/foundry/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -out/ -cache/ -broadcast/ -lib/ -.env diff --git a/cli/src/templates/default/foundry/README.md b/cli/src/templates/default/foundry/README.md deleted file mode 100644 index 795e06aa..00000000 --- a/cli/src/templates/default/foundry/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# {{projectName}} - -## Compose - -Foundry diamond starter scaffolded by the [Compose CLI](https://github.com/Perfect-Abstractions/Compose). Project can use the `@perfect-abstractions/compose` library for diamond infrastructure facets. - -### How to deploy - -`DeployScript` deploys `CounterFacet`, `DiamondInspectFacet`, and `DiamondUpgradeFacet`, then deploys `Diamond` with those facets and `msg.sender` as the owner. - -### Links -- [Docs](https://compose.diamonds/) -- [GitHub](https://github.com/Perfect-Abstractions/Compose) - ---- - -## Foundry usage - -### Build - -```sh -forge build -``` - -### Test - -```sh -forge test -``` - -### Format - -```sh -forge fmt -``` - -### Gas snapshots - -```sh -forge snapshot -``` - -### Anvil - -```sh -anvil -``` - -### Deploy - -```sh -forge script script/Deploy.s.sol:DeployScript --rpc-url --private-key -``` - -### Cast - -```sh -cast -``` - -### Help - -```sh -forge --help -anvil --help -cast --help -``` \ No newline at end of file diff --git a/cli/src/templates/default/foundry/foundry.toml b/cli/src/templates/default/foundry/foundry.toml deleted file mode 100644 index b83fc46b..00000000 --- a/cli/src/templates/default/foundry/foundry.toml +++ /dev/null @@ -1,9 +0,0 @@ -[profile.default] -src = "src" -out = "out" -libs = ["lib"] -optimizer = true -optimizer_runs = 200 - -[fmt] -line_length = 120 diff --git a/cli/src/templates/default/foundry/remappings.txt b/cli/src/templates/default/foundry/remappings.txt deleted file mode 100644 index 9352c32e..00000000 --- a/cli/src/templates/default/foundry/remappings.txt +++ /dev/null @@ -1 +0,0 @@ -@perfect-abstractions/compose/=lib/Compose/src/ diff --git a/cli/src/templates/default/foundry/script/Deploy.s.sol b/cli/src/templates/default/foundry/script/Deploy.s.sol deleted file mode 100644 index ac119f91..00000000 --- a/cli/src/templates/default/foundry/script/Deploy.s.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Script} from "forge-std/Script.sol"; -import {CounterFacet} from "../src/facets/CounterFacet.sol"; -import {Diamond} from "../src/Diamond.sol"; -import {DiamondInspectFacet} from "@perfect-abstractions/compose/diamond/DiamondInspectFacet.sol"; -import {DiamondUpgradeFacet} from "@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol"; - -contract DeployScript is Script { - function run() external { - vm.startBroadcast(); - - CounterFacet counterFacet = new CounterFacet(); - DiamondInspectFacet inspectFacet = new DiamondInspectFacet(); - DiamondUpgradeFacet upgradeFacet = new DiamondUpgradeFacet(); - - address[] memory facets = new address[](3); - facets[0] = address(counterFacet); - facets[1] = address(inspectFacet); - facets[2] = address(upgradeFacet); - - new Diamond(facets, msg.sender); - - vm.stopBroadcast(); - } -} diff --git a/cli/src/templates/default/foundry/src/Diamond.sol b/cli/src/templates/default/foundry/src/Diamond.sol deleted file mode 100644 index 2f927076..00000000 --- a/cli/src/templates/default/foundry/src/Diamond.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; -import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; - -contract Diamond { - constructor(address[] memory facets, address diamondOwner) { - DiamondMod.addFacets(facets); - OwnerDataMod.setContractOwner(diamondOwner); - } - - fallback() external payable { - DiamondMod.diamondFallback(); - } - - receive() external payable {} -} diff --git a/cli/src/templates/default/foundry/src/facets/CounterFacet.sol b/cli/src/templates/default/foundry/src/facets/CounterFacet.sol deleted file mode 100644 index 6b5d03ec..00000000 --- a/cli/src/templates/default/foundry/src/facets/CounterFacet.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -contract CounterFacet { - event Increment(uint256 by); - - bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); - - struct CounterStorage { - uint256 counter; - } - - function _getStorage() internal pure returns (CounterStorage storage s) { - bytes32 position = COUNTER_STORAGE_POSITION; - assembly { - s.slot := position - } - } - - function increment() external { - CounterStorage storage s = _getStorage(); - s.counter += 1; - emit Increment(1); - } - - function getCounter() external view returns (uint256) { - return _getStorage().counter; - } - - function exportSelectors() external pure returns (bytes memory) { - return bytes.concat(this.increment.selector, this.getCounter.selector); - } -} diff --git a/cli/src/templates/default/foundry/test/CounterFacet.t.sol b/cli/src/templates/default/foundry/test/CounterFacet.t.sol deleted file mode 100644 index 241d4877..00000000 --- a/cli/src/templates/default/foundry/test/CounterFacet.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Test} from "forge-std/Test.sol"; -import {CounterFacet} from "../src/facets/CounterFacet.sol"; -import {Diamond} from "../src/Diamond.sol"; - -contract CounterFacetTest is Test { - CounterFacet internal counter; - Diamond internal diamond; - - address internal owner = makeAddr("owner"); - - function setUp() public { - CounterFacet counterFacet = new CounterFacet(); - - address[] memory facets = new address[](1); - facets[0] = address(counterFacet); - - diamond = new Diamond(facets, owner); - counter = CounterFacet(address(diamond)); - } - - function test_increment() public { - counter.increment(); - assertEq(counter.getCounter(), 1); - } -} diff --git a/cli/src/templates/default/hardhat/ts/minimal/.gitignore b/cli/src/templates/default/hardhat/ts/minimal/.gitignore deleted file mode 100644 index 991a319e..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Node modules -/node_modules - -# Compilation output -/dist - -# pnpm deploy output -/bundle - -# Hardhat Build Artifacts -/artifacts - -# Hardhat compilation (v2) support directory -/cache - -# Typechain output -/types - -# Hardhat coverage reports -/coverage diff --git a/cli/src/templates/default/hardhat/ts/minimal/README.md b/cli/src/templates/default/hardhat/ts/minimal/README.md deleted file mode 100644 index 164983d5..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# {{projectName}} - -Hardhat 3 diamond starter scaffolded by the [Compose CLI](https://github.com/Perfect-Abstractions/Compose). Project can use the `@perfect-abstractions/compose` library for diamond infrastructure facets. - -Includes: -- `contracts/Diamond.sol` using Compose `DiamondMod` and `OwnerMod` -- `contracts/facets/CounterFacet.sol` with `increment`, `getCounter`, and `exportSelectors` - -Deploy each facet contract first, then deploy `Diamond` by passing the facet addresses and the owner address to the constructor. - -### Links -- [Docs](https://hardhat.org/docs/) -- [GitHub](https://github.com/NomicFoundation/hardhat) - -## Hardhat Usage -### Build -```sh -npx hardhat build -``` - -### Test -```sh -npx hardhat test -``` - -### Local node -```sh -npx hardhat node -``` - -This will launch a JSON-RPC server locally at `http://127.0.0.1:8545` - -### Help -```sh -npx hardhat --help -``` \ No newline at end of file diff --git a/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol deleted file mode 100644 index 2f927076..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/contracts/Diamond.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; -import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; - -contract Diamond { - constructor(address[] memory facets, address diamondOwner) { - DiamondMod.addFacets(facets); - OwnerDataMod.setContractOwner(diamondOwner); - } - - fallback() external payable { - DiamondMod.diamondFallback(); - } - - receive() external payable {} -} diff --git a/cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol deleted file mode 100644 index b612d60e..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/contracts/facets/CounterFacet.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -contract CounterFacet { - event Increment(uint256 by); - - bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); - - struct CounterStorage { - uint256 counter; - } - - function _getStorage() private pure returns (CounterStorage storage s) { - bytes32 position = COUNTER_STORAGE_POSITION; - assembly { - s.slot := position - } - } - - function increment() external { - CounterStorage storage s = _getStorage(); - s.counter += 1; - emit Increment(1); - } - - function getCounter() external view returns (uint256) { - return _getStorage().counter; - } - - function exportSelectors() external pure returns (bytes memory) { - return bytes.concat(this.increment.selector, this.getCounter.selector); - } -} diff --git a/cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts b/cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts deleted file mode 100644 index 82e7c620..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/hardhat.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from "hardhat/config"; - -export default defineConfig({ - solidity: { - version: "0.8.30", - }, -}); - diff --git a/cli/src/templates/default/hardhat/ts/minimal/package.json b/cli/src/templates/default/hardhat/ts/minimal/package.json deleted file mode 100644 index be8b3d04..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "{{projectName}}", - "version": "1.0.0", - "type": "module", - "devDependencies": { - "@types/node": "^22.19.13", - "hardhat": "^3.1.10", - "typescript": "~5.8.0" - } -} diff --git a/cli/src/templates/default/hardhat/ts/minimal/tsconfig.json b/cli/src/templates/default/hardhat/ts/minimal/tsconfig.json deleted file mode 100644 index 9b1380cc..00000000 --- a/cli/src/templates/default/hardhat/ts/minimal/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ -{ - "compilerOptions": { - "lib": ["es2023"], - "module": "node16", - "target": "es2022", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "moduleResolution": "node16", - "outDir": "dist" - } -} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore b/cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore deleted file mode 100644 index 991a319e..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Node modules -/node_modules - -# Compilation output -/dist - -# pnpm deploy output -/bundle - -# Hardhat Build Artifacts -/artifacts - -# Hardhat compilation (v2) support directory -/cache - -# Typechain output -/types - -# Hardhat coverage reports -/coverage diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/README.md b/cli/src/templates/default/hardhat/ts/mocha-ethers/README.md deleted file mode 100644 index 382231d7..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# {{projectName}} - -## Compose - -Hardhat 3 diamond starter scaffolded by the [Compose CLI](https://github.com/Perfect-Abstractions/Compose). Uses `mocha` for TypeScript tests and `ethers` for chain interactions and the `@perfect-abstractions/compose` library for diamond infrastructure facets. - -Includes Foundry-compatible Solidity tests, `mocha` integration tests, simulated networks (including OP-style chains in config), a `Diamond` built with Compose `DiamondMod` and `OwnerMod`, and a simple `CounterFacet`. - -### How to deploy - -The Ignition module `ignition/modules/Counter.ts` (`CounterDiamondModule`) deploys `CounterFacet`, `DiamondInspectFacet`, and `DiamondUpgradeFacet`, then deploys `Diamond` with those facets and `accounts[0]` as the owner. - -### Links - -- [Docs](https://compose.diamonds/) -- [GitHub](https://github.com/Perfect-Abstractions/Compose) - ---- - -## Hardhat usage - -### Build - -```sh -npx hardhat build -``` - -### Test - -```sh -npx hardhat test -``` - -Run only Solidity or only Mocha tests: - -```sh -npx hardhat test solidity -npx hardhat test mocha -``` - -### Launch a local Hardhat node - -To start a local Hardhat network node (an in-process Ethereum simulator), run: - -```sh -npx hardhat node -``` - -This will launch a JSON-RPC server locally at `http://127.0.0.1:8545` with unlocked test accounts and pre-funded balances. Your contracts can be deployed and tested against this running network by configuring your scripts or commands to use the local endpoint. - -In a separate terminal, you can then deploy or test against the local node by specifying the `--network localhost` option if needed: - - -### Deploy - -Deploy to a local chain: -```sh -npx hardhat ignition deploy ignition/modules/Counter.ts -``` - -To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use. - -You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable (less recommended). - -After configuring `SEPOLIA_PRIVATE_KEY` and network in `hardhat.config`: - -To set the `SEPOLIA_PRIVATE_KEY` variable using `hardhat-keystore`: - -```shell -npx hardhat keystore set SEPOLIA_PRIVATE_KEY -``` - -After setting the variable, you can run the deployment with the Sepolia network: - -```shell -npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts -``` - -### Cast - -```sh -cast -``` - -### Help - -```sh -npx hardhat --help -forge --help -anvil --help -cast --help -``` diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol deleted file mode 100644 index 2f927076..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/Diamond.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; -import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; - -contract Diamond { - constructor(address[] memory facets, address diamondOwner) { - DiamondMod.addFacets(facets); - OwnerDataMod.setContractOwner(diamondOwner); - } - - fallback() external payable { - DiamondMod.diamondFallback(); - } - - receive() external payable {} -} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol deleted file mode 100644 index b612d60e..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/facets/CounterFacet.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -contract CounterFacet { - event Increment(uint256 by); - - bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); - - struct CounterStorage { - uint256 counter; - } - - function _getStorage() private pure returns (CounterStorage storage s) { - bytes32 position = COUNTER_STORAGE_POSITION; - assembly { - s.slot := position - } - } - - function increment() external { - CounterStorage storage s = _getStorage(); - s.counter += 1; - emit Increment(1); - } - - function getCounter() external view returns (uint256) { - return _getStorage().counter; - } - - function exportSelectors() external pure returns (bytes memory) { - return bytes.concat(this.increment.selector, this.getCounter.selector); - } -} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol b/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol deleted file mode 100644 index bcd8e675..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/contracts/tests/CounterFacet.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import {Test} from "forge-std/Test.sol"; -import {CounterFacet} from "../facets/CounterFacet.sol"; -import {Diamond} from "../Diamond.sol"; - -contract CounterFacetTest is Test { - CounterFacet internal counter; - Diamond internal diamond; - - address internal owner = makeAddr("owner"); - - function setUp() public { - CounterFacet counterFacet = new CounterFacet(); - - address[] memory facets = new address[](1); - facets[0] = address(counterFacet); - - diamond = new Diamond(facets, owner); - counter = CounterFacet(address(diamond)); - } - - function test_increment() public { - counter.increment(); - assertEq(counter.getCounter(), 1); - } -} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts deleted file mode 100644 index a400f0d8..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/hardhat.config.ts +++ /dev/null @@ -1,43 +0,0 @@ -import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers"; -import { configVariable, defineConfig } from "hardhat/config"; - -export default defineConfig({ - plugins: [hardhatToolboxMochaEthersPlugin], - solidity: { - npmFilesToBuild: [ - "@perfect-abstractions/compose/diamond/DiamondInspectFacet.sol", - "@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol", - ], - profiles: { - default: { - version: "0.8.30", - }, - production: { - version: "0.8.30", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, - }, - }, - }, - networks: { - hardhatMainnet: { - type: "edr-simulated", - chainType: "l1", - }, - hardhatOp: { - type: "edr-simulated", - chainType: "op", - }, - sepolia: { - type: "http", - chainType: "l1", - url: configVariable("SEPOLIA_RPC_URL"), - accounts: [configVariable("SEPOLIA_PRIVATE_KEY")], - }, - }, -}); - diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts deleted file mode 100644 index e37b518c..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/ignition/modules/Counter.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; - -export default buildModule("CounterDiamondModule", (m) => { - const counterFacet = m.contract("CounterFacet"); - const inspectFacet = m.contract("DiamondInspectFacet"); - const upgradeFacet = m.contract("DiamondUpgradeFacet"); - - const owner = m.getAccount(0); - const diamond = m.contract("Diamond", [[counterFacet, inspectFacet, upgradeFacet], owner]); - - return { diamond, counterFacet, inspectFacet, upgradeFacet }; -}); diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/package.json b/cli/src/templates/default/hardhat/ts/mocha-ethers/package.json deleted file mode 100644 index 5f504c82..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "{{projectName}}", - "version": "1.0.0", - "type": "module", - "devDependencies": { - "@nomicfoundation/hardhat-ethers": "^4.0.5", - "@nomicfoundation/hardhat-ignition": "^3.0.8", - "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3", - "@types/chai": "^5.2.3", - "@types/chai-as-promised": "^8.0.2", - "@types/mocha": "^10.0.10", - "@types/node": "^22.19.13", - "chai": "^6.2.2", - "ethers": "^6.16.0", - "forge-std": "github:foundry-rs/forge-std#v1.9.4", - "hardhat": "^3.1.10", - "mocha": "^11.7.5", - "typescript": "~5.8.0" - } -} diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts deleted file mode 100644 index c3a4f7b2..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/scripts/send-op-tx.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { network } from "hardhat"; - -const { ethers } = await network.connect({ - network: "hardhatOp", - chainType: "op", -}); - -console.log("Sending transaction using the OP chain type"); - -const [sender] = await ethers.getSigners(); - -console.log("Sending 1 wei from", sender.address, "to itself"); - -console.log("Sending L2 transaction"); -const tx = await sender.sendTransaction({ - to: sender.address, - value: 1n, -}); - -await tx.wait(); - -console.log("Transaction sent successfully"); - diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts b/cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts deleted file mode 100644 index a5dbd535..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/test/Counter.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect } from "chai"; -import { network } from "hardhat"; - -const { ethers } = await network.connect(); - -describe("Counter", function () { - it("Increment the counter", async function () { - const counterFacet = await ethers.deployContract("CounterFacet"); - const [owner] = await ethers.getSigners(); - - const diamond = await ethers.deployContract("Diamond", [ - [ - await counterFacet.getAddress() - ], - owner.address, - ]); - - const counter = await ethers.getContractAt("CounterFacet", await diamond.getAddress()); - - await counter.increment(); - expect(await counter.getCounter()).to.equal(1n); - }); -}); - diff --git a/cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json b/cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json deleted file mode 100644 index 9b1380cc..00000000 --- a/cli/src/templates/default/hardhat/ts/mocha-ethers/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ -{ - "compilerOptions": { - "lib": ["es2023"], - "module": "node16", - "target": "es2022", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "moduleResolution": "node16", - "outDir": "dist" - } -} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore b/cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore deleted file mode 100644 index 991a319e..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Node modules -/node_modules - -# Compilation output -/dist - -# pnpm deploy output -/bundle - -# Hardhat Build Artifacts -/artifacts - -# Hardhat compilation (v2) support directory -/cache - -# Typechain output -/types - -# Hardhat coverage reports -/coverage diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/README.md b/cli/src/templates/default/hardhat/ts/node-runner-viem/README.md deleted file mode 100644 index 7d617aec..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# {{projectName}} - -## Compose - -Hardhat 3 diamond starter scaffolded by the [Compose CLI](https://github.com/Perfect-Abstractions/Compose). Uses the native Node.js test runner (`node:test`) for TypeScript tests and `viem` for chain interactions and the `@perfect-abstractions/compose` library for diamond infrastructure facets. - -Includes Foundry-compatible Solidity tests, `node:test` integration tests, simulated networks (including OP-style chains in config), a `Diamond` built with Compose `DiamondMod` and `OwnerMod`, and facets (`CounterFacet`, `DiamondInspectFacet`, `DiamondUpgradeFacet`). - -### How to deploy - -The Ignition module `ignition/modules/Counter.ts` (`CounterDiamondModule`) deploys `CounterFacet`, `DiamondInspectFacet`, and `DiamondUpgradeFacet`, then deploys `Diamond` with those facets and `accounts[0]` as the owner. - -### Links - -- [Docs](https://compose.diamonds/) -- [GitHub](https://github.com/Perfect-Abstractions/Compose) - ---- - -## Hardhat usage - -### Build - -```sh -npx hardhat build -``` - -### Test - -```sh -npx hardhat test -``` - -Run only Solidity or only Node.js tests: - -```sh -npx hardhat test solidity -npx hardhat test nodejs -``` - -### Launch a local Hardhat node - -To start a local Hardhat network node (an in-process Ethereum simulator), run: - -```sh -npx hardhat node -``` - -This will launch a JSON-RPC server locally at `http://127.0.0.1:8545` with unlocked test accounts and pre-funded balances. Your contracts can be deployed and tested against this running network by configuring your scripts or commands to use the local endpoint. - -In a separate terminal, you can then deploy or test against the local node by specifying the `--network localhost` option if needed: - -### Deploy - -Deploy to a local chain: -```sh -npx hardhat ignition deploy ignition/modules/Counter.ts -``` - -To run the deployment to Sepolia, you need an account with funds to send the transaction. The provided Hardhat configuration includes a Configuration Variable called `SEPOLIA_PRIVATE_KEY`, which you can use to set the private key of the account you want to use. - -You can set the `SEPOLIA_PRIVATE_KEY` variable using the `hardhat-keystore` plugin or by setting it as an environment variable (less recommended). - -After configuring `SEPOLIA_PRIVATE_KEY` and network in `hardhat.config`: - -To set the `SEPOLIA_PRIVATE_KEY` variable using `hardhat-keystore`: - -```shell -npx hardhat keystore set SEPOLIA_PRIVATE_KEY -``` - -After setting the variable, you can run the deployment with the Sepolia network: - -```shell -npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts -``` - -### Cast - -```sh -cast -``` - -### Help - -```sh -npx hardhat --help -forge --help -anvil --help -cast --help -``` diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol deleted file mode 100644 index 2f927076..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/Diamond.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod; -import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod; - -contract Diamond { - constructor(address[] memory facets, address diamondOwner) { - DiamondMod.addFacets(facets); - OwnerDataMod.setContractOwner(diamondOwner); - } - - fallback() external payable { - DiamondMod.diamondFallback(); - } - - receive() external payable {} -} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol deleted file mode 100644 index b612d60e..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/facets/CounterFacet.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.30; - -contract CounterFacet { - event Increment(uint256 by); - - bytes32 private constant COUNTER_STORAGE_POSITION = keccak256("compose.counter"); - - struct CounterStorage { - uint256 counter; - } - - function _getStorage() private pure returns (CounterStorage storage s) { - bytes32 position = COUNTER_STORAGE_POSITION; - assembly { - s.slot := position - } - } - - function increment() external { - CounterStorage storage s = _getStorage(); - s.counter += 1; - emit Increment(1); - } - - function getCounter() external view returns (uint256) { - return _getStorage().counter; - } - - function exportSelectors() external pure returns (bytes memory) { - return bytes.concat(this.increment.selector, this.getCounter.selector); - } -} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol b/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol deleted file mode 100644 index 053588b5..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/contracts/tests/CounterFacet.t.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.30; - -import {CounterFacet} from "../facets/CounterFacet.sol"; -import {Diamond} from "../Diamond.sol"; -import {Test} from "forge-std/Test.sol"; - -contract CounterTest is Test { - CounterFacet counter; - - address internal owner = makeAddr("owner"); - - function setUp() public { - CounterFacet counterFacet = new CounterFacet(); - - address[] memory facets = new address[](1); - facets[0] = address(counterFacet); - - Diamond diamond = new Diamond(facets, owner); - counter = CounterFacet(address(diamond)); - } - - function test_InitialValue() public view { - require(counter.getCounter() == 0, "Initial value should be 0"); - } - - function testFuzz_Inc(uint8 x) public { - for (uint8 i = 0; i < x; i++) { - counter.increment(); - } - require(counter.getCounter() == x, "Value after increment x times should be x"); - } -} - diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts deleted file mode 100644 index f68b2fe6..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/hardhat.config.ts +++ /dev/null @@ -1,43 +0,0 @@ -import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem"; -import { configVariable, defineConfig } from "hardhat/config"; - -export default defineConfig({ - plugins: [hardhatToolboxViemPlugin], - solidity: { - npmFilesToBuild: [ - "@perfect-abstractions/compose/diamond/DiamondInspectFacet.sol", - "@perfect-abstractions/compose/diamond/DiamondUpgradeFacet.sol", - ], - profiles: { - default: { - version: "0.8.30", - }, - production: { - version: "0.8.30", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, - }, - }, - }, - networks: { - hardhatMainnet: { - type: "edr-simulated", - chainType: "l1", - }, - hardhatOp: { - type: "edr-simulated", - chainType: "op", - }, - sepolia: { - type: "http", - chainType: "l1", - url: configVariable("SEPOLIA_RPC_URL"), - accounts: [configVariable("SEPOLIA_PRIVATE_KEY")], - }, - }, -}); - diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts deleted file mode 100644 index e37b518c..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/ignition/modules/Counter.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; - -export default buildModule("CounterDiamondModule", (m) => { - const counterFacet = m.contract("CounterFacet"); - const inspectFacet = m.contract("DiamondInspectFacet"); - const upgradeFacet = m.contract("DiamondUpgradeFacet"); - - const owner = m.getAccount(0); - const diamond = m.contract("Diamond", [[counterFacet, inspectFacet, upgradeFacet], owner]); - - return { diamond, counterFacet, inspectFacet, upgradeFacet }; -}); diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/package.json b/cli/src/templates/default/hardhat/ts/node-runner-viem/package.json deleted file mode 100644 index a4c9106c..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "{{projectName}}", - "version": "1.0.0", - "type": "module", - "devDependencies": { - "@nomicfoundation/hardhat-ignition": "^3.0.8", - "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2", - "@types/node": "^22.19.13", - "forge-std": "github:foundry-rs/forge-std#v1.9.4", - "hardhat": "^3.1.10", - "typescript": "~5.8.0", - "viem": "^2.47.0" - } -} diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts deleted file mode 100644 index 5945f966..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/scripts/send-op-tx.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { network } from "hardhat"; - -const { viem } = await network.connect({ - network: "hardhatOp", - chainType: "op", -}); - -console.log("Sending transaction using the OP chain type"); - -const publicClient = await viem.getPublicClient(); -const [senderClient] = await viem.getWalletClients(); - -console.log("Sending 1 wei from", senderClient.account.address, "to itself"); - -const l1Gas = await publicClient.estimateL1Gas({ - account: senderClient.account.address, - to: senderClient.account.address, - value: 1n, -}); - -console.log("Estimated L1 gas:", l1Gas); - -console.log("Sending L2 transaction"); -const tx = await senderClient.sendTransaction({ - to: senderClient.account.address, - value: 1n, -}); - -await publicClient.waitForTransactionReceipt({ hash: tx }); - -console.log("Transaction sent successfully"); - diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts b/cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts deleted file mode 100644 index bc107d87..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/test/Counter.ts +++ /dev/null @@ -1,25 +0,0 @@ -import assert from "node:assert/strict"; -import { describe, it } from "node:test"; - -import { network } from "hardhat"; - -describe("Counter", async function () { - const { viem } = await network.connect(); - const walletClients = await viem.getWalletClients(); - const owner = walletClients[0]; - - it("Increment the counter", async function () { - const counterFacet = await viem.deployContract("CounterFacet"); - - const diamond = await viem.deployContract("Diamond", [ - [counterFacet.address], - owner.account.address, - ]); - - const counter = await viem.getContractAt("CounterFacet", diamond.address); - - await counter.write.increment(); - assert.equal(await counter.read.getCounter(), 1n); - }); -}); - diff --git a/cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json b/cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json deleted file mode 100644 index 9b1380cc..00000000 --- a/cli/src/templates/default/hardhat/ts/node-runner-viem/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -/* Based on https://github.com/tsconfig/bases/blob/501da2bcd640cf95c95805783e1012b992338f28/bases/node22.json */ -{ - "compilerOptions": { - "lib": ["es2023"], - "module": "node16", - "target": "es2022", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "moduleResolution": "node16", - "outDir": "dist" - } -} diff --git a/cli/src/templates/default/template.json b/cli/src/templates/default/template.json deleted file mode 100644 index 5e1848b1..00000000 --- a/cli/src/templates/default/template.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "default", - "name": "Counter", - "description": "Simple diamond with a counter facet", - "variants": [ - "default-foundry", - "default-hardhat-minimal", - "default-hardhat-mocha-ethers", - "default-hardhat-node-runner-viem" - ], - "compatibility": { - "frameworks": ["foundry", "hardhat"] - } -} diff --git a/cli/src/templates/deploy/foundry-deploy.sol b/cli/src/templates/deploy/foundry-deploy.sol new file mode 100644 index 00000000..64c93ec4 --- /dev/null +++ b/cli/src/templates/deploy/foundry-deploy.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/* Compose + * https://compose.diamonds + */ + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {Diamond} from "../src/Diamond.sol"; +{{IMPORTS}} + +contract DeployScript is Script { + function setUp() public {} + + function run() public returns (Diamond diamond) { + vm.startBroadcast(); + + address[] memory facets = new address[]({{FACET_COUNT}}); + + // Base facet generation. +{{BASE_LINES}} + + // Library facet generation. +{{LIBRARY_LINES}} + + // Define diamond proxy. + diamond = new Diamond(facets); + console.log("Diamond:", address(diamond)); + + vm.stopBroadcast(); + } +} diff --git a/cli/src/templates/deploy/hardhat-ethers-deploy.ts b/cli/src/templates/deploy/hardhat-ethers-deploy.ts new file mode 100644 index 00000000..919d384e --- /dev/null +++ b/cli/src/templates/deploy/hardhat-ethers-deploy.ts @@ -0,0 +1,26 @@ +import { network } from "hardhat"; + +const { ethers, networkName } = await network.create(); + +async function deploy() { + console.log(`Deploying Diamond to ${networkName}...`); + + const facets: string[] = []; + + // Base facet generation. +{{BASE_LINES}} + + // Library facet generation. +{{LIBRARY_LINES}} + + // Define diamond proxy. + const diamond = await ethers.deployContract("Diamond", [facets]); + await diamond.waitForDeployment(); + + console.log("Diamond:", await diamond.getAddress()); +} + +deploy().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/cli/src/templates/deploy/hardhat-viem-deploy.ts b/cli/src/templates/deploy/hardhat-viem-deploy.ts new file mode 100644 index 00000000..a15fbdeb --- /dev/null +++ b/cli/src/templates/deploy/hardhat-viem-deploy.ts @@ -0,0 +1,25 @@ +import { network } from "hardhat"; + +const { viem, networkName } = await network.create(); + +async function deploy() { + console.log(`Deploying Diamond to ${networkName}...`); + + const facets: `0x${string}`[] = []; + + // Base facet generation. +{{BASE_LINES}} + + // Library facet generation. +{{LIBRARY_LINES}} + + // Define diamond proxy. + const diamond = await viem.deployContract("Diamond", [facets]); + + console.log("Diamond:", diamond.address); +} + +deploy().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/cli/src/templates/diamond/diamond.sol b/cli/src/templates/diamond/diamond.sol new file mode 100644 index 00000000..9d439a8d --- /dev/null +++ b/cli/src/templates/diamond/diamond.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity {{SOLIDITY_PRAGMA}}; + +/* Compose + * https://compose.diamonds + */ + +{{IMPORTS}} + +contract {{CONTRACT_NAME}} { + constructor(address[] memory _facets) { +{{CONSTRUCTOR_BLOCKS}} + } + + fallback() external payable { + DiamondMod.diamondFallback(); + } + + receive() external payable {} +} diff --git a/cli/src/templates/examples/ERC20IdentifierCollisionError.sol b/cli/src/templates/examples/ERC20IdentifierCollisionError.sol new file mode 100644 index 00000000..be77e7f4 --- /dev/null +++ b/cli/src/templates/examples/ERC20IdentifierCollisionError.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +// TEST FIXTURE: This facet intentionally has identifier collisions. +// Used by the CLI to validate that identifier collisions are detected. + +contract ERC20IdentifierCollisionError { + bytes32 constant STORAGE_POSITION = keccak256("erc20.identifier"); + + struct Data { + uint256 value; + mapping(address => uint256) values; + } + + function getStorage() internal pure returns (Data storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + // ERROR: Two functions with the same name but different signatures + function getValue() external view returns (uint256) { + return getStorage().value; + } + + function getValue(address _account) external view returns (uint256) { + return getStorage().values[_account]; + } + + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat( + this.getValue.selector, + this.getValue(address).selector + ); + } +} diff --git a/cli/src/templates/examples/ERC20MissingExportSelector.sol b/cli/src/templates/examples/ERC20MissingExportSelector.sol new file mode 100644 index 00000000..5ddc5186 --- /dev/null +++ b/cli/src/templates/examples/ERC20MissingExportSelector.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +// TEST FIXTURE: This facet intentionally does NOT implement exportSelectors(). +// Used by the CLI to validate that missing exportSelectors() is detected. + +contract ERC20MissingExportSelector { + bytes32 constant STORAGE_POSITION = keccak256("erc20.missing"); + + struct Data { + uint256 value; + } + + function getStorage() internal pure returns (Data storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function getValue() external view returns (uint256) { + return getStorage().value; + } + + function setValue(uint256 _value) external { + getStorage().value = _value; + } +} diff --git a/cli/src/templates/examples/ERC20SelectorCollisionError.sol b/cli/src/templates/examples/ERC20SelectorCollisionError.sol new file mode 100644 index 00000000..7bcb235f --- /dev/null +++ b/cli/src/templates/examples/ERC20SelectorCollisionError.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.30; + +/* Compose + * https://compose.diamonds + */ + +// TEST FIXTURE: This facet intentionally exports the same selector twice. +// Used by the CLI to validate that selector collisions are detected. + +contract ERC20SelectorCollisionError { + bytes32 constant STORAGE_POSITION = keccak256("erc20.collision"); + + struct Data { + uint256 value; + } + + function getStorage() internal pure returns (Data storage s) { + bytes32 position = STORAGE_POSITION; + assembly { + s.slot := position + } + } + + function getValue() external view returns (uint256) { + return getStorage().value; + } + + function setValue(uint256 _value) external { + getStorage().value = _value; + } + + // ERROR: exportSelectors() exports this.getValue.selector twice + function exportSelectors() external pure returns (bytes memory) { + return bytes.concat(this.getValue.selector, this.getValue.selector); + } +} diff --git a/cli/src/templates/readme/foundry-readme.md b/cli/src/templates/readme/foundry-readme.md new file mode 100644 index 00000000..78a23c9c --- /dev/null +++ b/cli/src/templates/readme/foundry-readme.md @@ -0,0 +1,50 @@ +# {{PROJECT_NAME}} + +Scaffolded by [Compose CLI](https://compose.diamonds) - The open-source toolkit for building modular smart contracts system on the Diamond architecture. + +## Prerequisites + +- [Foundry](https://book.getfoundry.sh/getting-started/installation) + +## Build + +```shell +forge build +``` + +## Test + +```shell +forge test +``` + +## Deploy Locally + +Start a local Ethereum node: + +```shell +anvil +``` + +Deploy to the local network: + +```shell +forge script script/Deploy.s.sol:DeployScript --rpc-url http://localhost:8545 --private-key --broadcast +``` + +## Deploy + +```shell +forge script script/Deploy.s.sol:DeployScript --rpc-url --private-key --broadcast +``` + +## Format + +```shell +forge fmt +``` + +## Learn More + +- [Foundry Documentation](https://book.getfoundry.sh/) +- [Compose Documentation](https://compose.diamonds) diff --git a/cli/src/templates/readme/hardhat-readme.md b/cli/src/templates/readme/hardhat-readme.md new file mode 100644 index 00000000..52949c44 --- /dev/null +++ b/cli/src/templates/readme/hardhat-readme.md @@ -0,0 +1,50 @@ +# {{PROJECT_NAME}} + +Scaffolded by [Compose CLI](https://compose.diamonds) - The open-source toolkit for building modular smart contracts system on the Diamond architecture. + +## Prerequisites + +- [Node.js](https://nodejs.org/) (v20 or later) + +## Install Dependencies + +```shell +npm install +``` + +## Build + +```shell +npm run build +``` + +## Test + +```shell +npm run test +``` + +## Deploy Locally + +Start a local Ethereum node: + +```shell +npx hardhat node +``` + +Deploy to the local network (in a separate terminal): + +```shell +npx hardhat run scripts/deploy.ts --network localhost +``` + +## Deploy + +```shell +npx hardhat run scripts/deploy.ts --network +``` + +## Learn More + +- [Hardhat Documentation](https://hardhat.org/docs) +- [Compose Documentation](https://compose.diamonds) diff --git a/cli/src/templates/test/foundry-test.sol b/cli/src/templates/test/foundry-test.sol new file mode 100644 index 00000000..afb772dd --- /dev/null +++ b/cli/src/templates/test/foundry-test.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/* Compose + * https://compose.diamonds + */ + +import {Test} from "forge-std/Test.sol"; +import {Diamond} from "../src/Diamond.sol"; +{{IMPORTS}} + +contract DiamondTest is Test { + Diamond diamond; + + function setUp() public { + address[] memory facets = new address[]({{FACET_COUNT}}); + + // Base facet generation. +{{BASE_LINES}} + + // Library facet generation. +{{LIBRARY_LINES}} + + diamond = new Diamond(facets); + } + + function test_inspect_facetAddresses() public view { + DiamondInspectFacet inspect = DiamondInspectFacet(address(diamond)); + address[] memory addresses = inspect.facetAddresses(); + assertEq(addresses.length, {{FACET_COUNT}}); + } +} diff --git a/cli/src/templates/test/hardhat-ethers-test.ts b/cli/src/templates/test/hardhat-ethers-test.ts new file mode 100644 index 00000000..f09eb927 --- /dev/null +++ b/cli/src/templates/test/hardhat-ethers-test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import { network } from "hardhat"; + +const { ethers } = await network.create(); + +describe("Diamond", function () { + let diamondAddress: string; + + before(async function () { + const facets: string[] = []; + + // Base facet generation. +{{BASE_LINES}} + + // Library facet generation. +{{LIBRARY_LINES}} + + const diamond = await ethers.deployContract("Diamond", [facets]); + await diamond.waitForDeployment(); + diamondAddress = await diamond.getAddress(); + }); + + it("inspect: facetAddresses returns correct count", async function () { + const inspect = await ethers.getContractAt("DiamondInspectFacet", diamondAddress); + const addresses = await inspect.facetAddresses(); + expect(addresses.length).to.equal({{FACET_COUNT}}); + }); +}); diff --git a/cli/src/templates/test/hardhat-viem-test.ts b/cli/src/templates/test/hardhat-viem-test.ts new file mode 100644 index 00000000..cd06913b --- /dev/null +++ b/cli/src/templates/test/hardhat-viem-test.ts @@ -0,0 +1,28 @@ +import assert from "node:assert"; +import { describe, test, before } from "node:test"; +import { network } from "hardhat"; + +const { viem } = await network.create(); + +describe("Diamond", () => { + let diamondAddress: `0x${string}`; + + before(async () => { + const facets: `0x${string}`[] = []; + + // Base facet generation. +{{BASE_LINES}} + + // Library facet generation. +{{LIBRARY_LINES}} + + const diamond = await viem.deployContract("Diamond", [facets]); + diamondAddress = diamond.address; + }); + + test("inspect: facetAddresses returns correct count", async () => { + const inspect = await viem.getContractAt("DiamondInspectFacet", diamondAddress); + const addresses = await inspect.read.facetAddresses(); + assert.strictEqual(addresses.length, {{FACET_COUNT}}); + }); +}); diff --git a/cli/src/utils/arrays.ts b/cli/src/utils/arrays.ts new file mode 100644 index 00000000..9a9508ab --- /dev/null +++ b/cli/src/utils/arrays.ts @@ -0,0 +1,28 @@ +/** + * Deduplicates an array by a key function, keeping the first occurrence of each unique key. + * + * @param items - Array of items to deduplicate. + * @param keyFn - Function that extracts the deduplication key from an item. + * @returns A new array with only the first occurrence of each unique key. + */ +export function dedupeBy(items: T[], keyFn: (item: T) => string): T[] { + const seen = new Set(); + return items.filter((item) => { + const key = keyFn(item); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); +} + +/** + * Checks whether one array is a prefix of another. + * + * @param prefix - The potential prefix array. + * @param array - The array to check against. + * @returns True if `prefix` matches the beginning of `array`. + */ +export function isArrayPrefix(prefix: T[], array: T[]): boolean { + if (prefix.length > array.length) return false; + return prefix.every((value, index) => array[index] === value); +} diff --git a/cli/src/utils/codegen.ts b/cli/src/utils/codegen.ts new file mode 100644 index 00000000..239e0dd7 --- /dev/null +++ b/cli/src/utils/codegen.ts @@ -0,0 +1,14 @@ +import fs from "node:fs/promises"; +import path from "node:path"; + +/** + * Loads a template file from the templates directory. + * + * @param subdir - The template subdirectory (e.g. "diamond", "deploy"). + * @param name - The template file name (e.g. "diamond.sol"). + * @returns The template content as a string. + */ +export async function loadTemplate(subdir: string, name: string): Promise { + const templatePath = path.resolve(process.cwd(), "src/templates", subdir, name); + return fs.readFile(templatePath, "utf8"); +} diff --git a/cli/src/utils/errors.js b/cli/src/utils/errors.js deleted file mode 100644 index d6cdbf7e..00000000 --- a/cli/src/utils/errors.js +++ /dev/null @@ -1,25 +0,0 @@ -const { logger } = require("./logger"); - -function normalizeError(error) { - if (error instanceof Error) { - return error; - } - - return new Error(String(error)); -} - -function exitWithError(error) { - const normalized = normalizeError(error); - logger.error(normalized.message); - - if (process.env.DEBUG === "1" && normalized.stack) { - logger.plain(normalized.stack); - } - - process.exitCode = 1; -} - -module.exports = { - normalizeError, - exitWithError, -}; diff --git a/cli/src/utils/errors.ts b/cli/src/utils/errors.ts new file mode 100644 index 00000000..1dc7c1a7 --- /dev/null +++ b/cli/src/utils/errors.ts @@ -0,0 +1,28 @@ +/** + * Error normalizer + * @param error + * @returns Normalized error + */ +function normalizeError(error: unknown): Error { + if (error instanceof Error) { + return error; + } + return new Error(String(error)); +} + +/** + * Exit Process with Normalized Error + * @param error + */ +function exitWithError(error: unknown): void { + const normalized = normalizeError(error); + console.error(normalized.message); + + if (process.env.DEBUG === "1" && normalized.stack) { + console.log(normalized.stack); + } + + process.exitCode = 1; +} + +export { normalizeError, exitWithError }; \ No newline at end of file diff --git a/cli/src/utils/exec.js b/cli/src/utils/exec.js deleted file mode 100644 index 9019a1ff..00000000 --- a/cli/src/utils/exec.js +++ /dev/null @@ -1,24 +0,0 @@ -const { spawn } = require("node:child_process"); - -function runCommand(command, args, options = {}) { - return new Promise((resolve, reject) => { - const child = spawn(command, args, { - stdio: "inherit", - ...options, - }); - - child.on("error", reject); - child.on("exit", (code) => { - if (code === 0) { - resolve(); - return; - } - - reject(new Error(`Command failed: ${command} ${args.join(" ")} (exit ${code})`)); - }); - }); -} - -module.exports = { - runCommand, -}; diff --git a/cli/src/utils/exec.ts b/cli/src/utils/exec.ts new file mode 100644 index 00000000..ab4ed5ac --- /dev/null +++ b/cli/src/utils/exec.ts @@ -0,0 +1,73 @@ +import { spawn } from "node:child_process"; +import fs from "node:fs/promises"; +import path from "node:path"; + +/** + * Resolves a command string to its executable path. + * Currently a passthrough; can be extended to handle + * PATH lookups, nvm version resolution, or other logic. + * + * @param command - The command to resolve. + * @returns The resolved command string. + */ +function resolveCommand(command: string): string { + return command; +} + +/** + * Spawns a child process with the given command and arguments. + * Returns a Promise that resolves when the process exits with code 0, + * or rejects on non-zero exit or spawn errors. + * On Windows, uses shell mode for npm/npx to avoid .cmd extension issues. + * + * @param command - The command to execute. + * @param args - Arguments to pass to the command. + * @param options - Optional spawn options (e.g., working directory). + * @returns A Promise that resolves on success or rejects on failure. + */ +export function runCommand(command: string, args: string[], options?: { cwd?: string }): Promise { + return new Promise((resolve, reject) => { + const resolvedCommand = resolveCommand(command); + const useShell = process.platform === "win32" && (command === "npm" || command === "npx"); + const child = spawn(resolvedCommand, args, { + stdio: "inherit", + shell: useShell, + ...options, + }); + child.on("error", reject); + child.on("exit", (code) => { + if (code === 0) { + resolve(); + return; + } + reject(new Error(`Command failed: ${command} ${args.join(" ")} (exit ${code})`)); + }); + }); +} + +/** + * Checks whether a binary exists in the system PATH. + * + * @param binaryName - Name of the binary to find (e.g., "node", "forge"). + * @throws {Error} If the binary is not found in PATH. + */ +export async function isBinaryInPath(binaryName: string): Promise { + const pathEnv = process.env.PATH || ""; + const separator = process.platform === "win32" ? ";" : ":"; + const paths = pathEnv.split(separator); + const extensions = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]; + + for (const currentPath of paths) { + for (const extension of extensions) { + const candidate = path.join(currentPath, `${binaryName}${extension}`); + try { + await fs.access(candidate); + return; + } catch { + continue; + } + } + } + + throw new Error(`${binaryName} not found in PATH. Please install ${binaryName} and try again.`); +} diff --git a/cli/src/utils/files.ts b/cli/src/utils/files.ts new file mode 100644 index 00000000..a27a94f3 --- /dev/null +++ b/cli/src/utils/files.ts @@ -0,0 +1,178 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { parseSolidityImports } from "./solidityText"; + +/** + * Checks whether a filesystem path exists without throwing. + * + * @param target - The filesystem path to check. + * @returns `true` if the path is accessible, `false` otherwise. + */ +export async function pathExists(target: string): Promise { + try { + await fs.access(target); + return true; + } catch { + return false; + } +} + +/** + * Returns every file path that cannot be accessed, preserving input order. + * + * @param filePaths - An iterable of file paths to check. + * @returns A Promise resolving to an array of paths that do not exist. + */ +export async function findMissingFiles(filePaths: Iterable): Promise { + const paths = [...filePaths]; + const exists = await Promise.all(paths.map((filePath) => pathExists(filePath))); + return paths.filter((_, index) => !exists[index]); +} + +/** + * Copies a file only when the destination does not already exist. + * Creates any intermediate directories as needed. + * + * @param from - The source file path to copy from. + * @param to - The destination file path to copy to. + */ +export async function copyFileIfMissing(from: string, to: string): Promise { + try { + await fs.access(to); + return; + } catch { + // destination does not exist, continue + } + await fs.mkdir(path.dirname(to), { recursive: true }); + await fs.copyFile(from, to); +} + +/** + * Writes text content only when the target file does not already exist. + * Creates any intermediate directories as needed. + * + * @param to - The destination file path to write to. + * @param content - The text content to write. + */ +export async function writeFileIfMissing(to: string, content: string): Promise { + try { + await fs.access(to); + return; + } catch { + // destination does not exist, continue + } + await fs.mkdir(path.dirname(to), { recursive: true }); + await fs.writeFile(to, content, "utf8"); +} + +/** + * Converts a platform-specific path to POSIX format using forward slashes. + * + * @param value - The file system path to convert. + * @returns The path with all backslashes replaced by forward slashes. + */ +export function toPosixPath(value: string): string { + return value.replace(/\\/g, "/"); +} + +/** + * Converts a relative path to an import path format. + * Ensures the path uses forward slashes and starts with "./" if it doesn't already. + * + * @param relativePath - The relative path to convert. + * @returns The path in import format (e.g., "./path/to/file"). + */ +export function toRelativeImport(relativePath: string): string { + const posixPath = toPosixPath(relativePath); + return posixPath.startsWith(".") ? posixPath : `./${posixPath}`; +} + +/** + * Checks whether a directory is empty, optionally ignoring specific entries. + * + * @param dirPath - The directory path to check. + * @param ignoredEntries - Array of entry names to ignore (e.g., [".git"]). + * @returns True if the directory is empty after filtering ignored entries. + */ +export async function isDirectoryEmpty(dirPath: string, ignoredEntries: string[] = []): Promise { + const entries = await fs.readdir(dirPath); + const nonIgnored = entries.filter((entry) => !ignoredEntries.includes(entry)); + return nonIgnored.length === 0; +} + +/** + * Searches for a file by walking up the directory tree from the given start path. + * + * @param startDir - The directory to start searching from. + * @param fileName - The name of the file to find (e.g., "compose.json"). + * @returns The full path to the file, or null if not found. + */ +export async function findFileAncestor(startDir: string, fileName: string): Promise { + let currentDir = startDir; + const root = path.parse(currentDir).root; + + while (currentDir !== root) { + const candidate = path.join(currentDir, fileName); + try { + await fs.access(candidate); + return candidate; + } catch { + // Not found, continue up + } + currentDir = path.dirname(currentDir); + } + + const rootCandidate = path.join(root, fileName); + try { + await fs.access(rootCandidate); + return rootCandidate; + } catch { + return null; + } +} + +/** + * Extracts the package name from an import path. + * Handles both scoped packages (@scope/package) and regular packages. + * + * @param importPath - The import path (e.g., "@scope/package/subpath" or "package/subpath"). + * @returns The package name (e.g., "@scope/package" or "package"). + */ +export function parsePackageName(importPath: string): string { + const parts = importPath.split("/"); + if (parts[0].startsWith("@")) { + return parts.slice(0, 2).join("/"); + } + return parts[0]; +} + +/** + * Resolves the transitive closure of local Solidity imports reachable from a set of seed source files. + * Follows relative imports (`./` or `../`) recursively, skipping already-visited files. + * + * @param seedSources - An array of Solidity source file paths to start traversal from. + * @returns A Promise resolving to a `Set` of all resolved local file paths. + */ +export async function resolveLocalSolidityImportClosure(seedSources: string[]): Promise> { + const visited = new Set(); + const stack = [...seedSources]; + + while (stack.length > 0) { + const file = path.resolve(stack.pop() as string); + if (visited.has(file)) continue; + visited.add(file); + + const code = await fs.readFile(file, "utf8"); + for (const specifier of parseSolidityImports(code)) { + if (!specifier.startsWith(".")) { + continue; + } + const dep = path.resolve(path.dirname(file), specifier); + if (!visited.has(dep)) { + stack.push(dep); + } + } + } + + return visited; +} diff --git a/cli/src/utils/helpText.js b/cli/src/utils/helpText.js deleted file mode 100644 index 9ce1b23b..00000000 --- a/cli/src/utils/helpText.js +++ /dev/null @@ -1,29 +0,0 @@ -const pkg = require("../../package.json"); -const { COMPOSE_DOCS_URL } = require("../config/constants"); - -const HELP_TEXT = ` -Compose CLI v${pkg.version} - -Scaffolds Diamond-based projects using the Compose Library - -Usage: - compose init [options] - compose list-templates - compose --version | -v - compose update - -Options: - --name - --template - --framework - --language - --install-deps | --no-install-deps - --yes - --help - -For more information about the Compose, see: ${COMPOSE_DOCS_URL} -`; - -module.exports = { - HELP_TEXT, -}; \ No newline at end of file diff --git a/cli/src/utils/logger.js b/cli/src/utils/logger.js deleted file mode 100644 index 3d18bba6..00000000 --- a/cli/src/utils/logger.js +++ /dev/null @@ -1,26 +0,0 @@ -const pc = require("picocolors"); - -const logger = { - info(message) { - console.log(pc.cyan(message)); - }, - success(message) { - console.log(pc.green(message)); - }, - warn(message) { - console.warn(pc.yellow(message)); - }, - brightYellow(message) { - console.warn(pc.bold(pc.yellowBright(message))); - }, - error(message) { - console.error(pc.red(message)); - }, - plain(message) { - console.log(message); - }, -}; - -module.exports = { - logger, -}; diff --git a/cli/src/utils/composeAsciiHeader.js b/cli/src/utils/metadata.ts similarity index 77% rename from cli/src/utils/composeAsciiHeader.js rename to cli/src/utils/metadata.ts index de788527..fec48f66 100644 --- a/cli/src/utils/composeAsciiHeader.js +++ b/cli/src/utils/metadata.ts @@ -1,4 +1,7 @@ -const COMPOSE_HEADER = ` +export const COMPOSE_DOCS_URL = "https://compose.diamonds/"; +export const VERSION = "0.1.0"; + +export const COMPOSE_HEADER = ` _____ ____ __ __ _____ ____ _____ ______ _____ _ _____ / ____/ __ \\| \\/ | __ \\ / __ \\ / ____| ____| / ____| | |_ _| | | | | | | \\ / | |__) | | | | (___ | |__ | | | | | | @@ -6,8 +9,6 @@ const COMPOSE_HEADER = ` | |___| |__| | | | | | | |__| |____) | |____ | |____| |____ _| |_ \\_____\\____/|_| |_|_| \\____/|_____/|______| \\_____|______|_____| - ` + `; + -module.exports = { - COMPOSE_HEADER, -}; \ No newline at end of file diff --git a/cli/src/utils/objects.ts b/cli/src/utils/objects.ts new file mode 100644 index 00000000..dede7394 --- /dev/null +++ b/cli/src/utils/objects.ts @@ -0,0 +1,14 @@ +/** + * Checks structural equality of two values via JSON serialization. + * + * @param left - First value. + * @param right - Second value. + * @returns `true` if both values are deeply equal by JSON comparison. + * + * @remarks + * Limitations: key order matters, `undefined` values are ignored, + * and `Date`/`Map`/`Set` are not handled correctly. + */ +export function isDeepEqual(left: unknown, right: unknown): boolean { + return JSON.stringify(left) === JSON.stringify(right); +} diff --git a/cli/src/utils/prompts/initUtils.js b/cli/src/utils/prompts/initUtils.js deleted file mode 100644 index 85ac0987..00000000 --- a/cli/src/utils/prompts/initUtils.js +++ /dev/null @@ -1,29 +0,0 @@ -const templateConfig = require("../../config/templates.json"); -const { assertDirectoryEmpty } = require("../../scaffold/utils/fileManager"); - -function getTemplateChoices() { - const list = templateConfig.templates || []; - if (list.length === 0) { - return [{ name: "Default", value: "default" }]; - } - return list.map((t) => ({ name: t.name, value: t.id })); -} - -async function validateProjectLocation(input) { - if (input !== ".") { - return true; - } - - try { - await assertDirectoryEmpty(process.cwd()); - return true; - } catch { - return 'Current directory must be empty (or only .git) when using ".".'; - } -} - -module.exports = { - getTemplateChoices, - validateProjectLocation, -}; - diff --git a/cli/src/utils/regex.ts b/cli/src/utils/regex.ts new file mode 100644 index 00000000..8973db37 --- /dev/null +++ b/cli/src/utils/regex.ts @@ -0,0 +1,10 @@ +/** + * Escapes special regex characters in a string so it can be safely + * embedded in a `RegExp` pattern without altering the intended match. + * + * @param value - The user-provided string to escape. + * @returns The escaped string safe for use in a RegExp. + */ +export function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} diff --git a/cli/src/utils/soliditySources.ts b/cli/src/utils/soliditySources.ts new file mode 100644 index 00000000..5214feb9 --- /dev/null +++ b/cli/src/utils/soliditySources.ts @@ -0,0 +1,71 @@ +import path from "node:path"; + +/** Prefix used to identify Compose package imports. */ +export const COMPOSE_PACKAGE_PREFIX = "@perfect-abstractions/compose/"; +const CLI_COMPOSE_PATH = "./node_modules/@perfect-abstractions/compose/"; +const LOCAL_TEMPLATE_PREFIX = "./src/templates/"; + +/** + * Identifies catalog paths that should resolve through the installed Compose package. + * + * @param sourcePath - The catalog source path to test. + * @returns `true` if the path starts with the Compose package prefix. + */ +export function isComposePackagePath(sourcePath: string): boolean { + return sourcePath.startsWith(COMPOSE_PACKAGE_PREFIX); +} + +/** + * Returns the path segment inside the Compose package for package imports. + * + * @param sourcePath - A Compose package path (must start with {@link COMPOSE_PACKAGE_PREFIX}). + * @returns The subpath after the package prefix. + * @throws {Error} If the path is not a Compose package path. + */ +export function composePackageSubpath(sourcePath: string): string { + if (!isComposePackagePath(sourcePath)) { + throw new Error(`Not a Compose package path: ${sourcePath}`); + } + + return sourcePath.slice(COMPOSE_PACKAGE_PREFIX.length); +} + +/** + * Converts old local template paths to Compose package imports while preserving local examples. + * + * @param sourcePath - The catalog source path to convert. + * @returns The converted path (package import or unchanged local path). + */ +export function toComposePackagePath(sourcePath: string): string { + if (!sourcePath.startsWith(LOCAL_TEMPLATE_PREFIX)) { + return sourcePath; + } + + return `${COMPOSE_PACKAGE_PREFIX}${sourcePath.slice(LOCAL_TEMPLATE_PREFIX.length)}`; +} + +/** + * Resolves a catalog Solidity path to a local file the CLI can read for validation. + * Package paths resolve from the CLI's own `node_modules/@perfect-abstractions/compose/`. + * Local paths resolve from the CLI's `src/templates/` directory. + * + * @param sourcePath - The catalog source path to resolve. + * @returns The absolute file path on disk. + */ +export function resolveCatalogSourceForRead(sourcePath: string): string { + if (isComposePackagePath(sourcePath)) { + return path.resolve(process.cwd(), CLI_COMPOSE_PATH, composePackageSubpath(sourcePath)); + } + + return path.resolve(process.cwd(), sourcePath); +} + +/** + * Returns the Solidity contract name implied by a catalog source path. + * + * @param sourcePath - The source file path (e.g., `contracts/Foo.sol`). + * @returns The filename without its extension. + */ +export function contractNameFromSourcePath(sourcePath: string): string { + return path.basename(sourcePath, path.extname(sourcePath)); +} diff --git a/cli/src/utils/solidityText.ts b/cli/src/utils/solidityText.ts new file mode 100644 index 00000000..f9122fbc --- /dev/null +++ b/cli/src/utils/solidityText.ts @@ -0,0 +1,247 @@ +import { escapeRegExp } from "./regex"; + +/** + * Describes a parsed public or external Solidity function. + */ +export type SolidityFunctionInfo = { + /** The function name. */ + name: string; + /** The normalized canonical signature (e.g., `transfer(address,uint256)`). */ + signature: string; + /** The function visibility. */ + visibility: "external" | "public"; +}; + +/** + * Parses Solidity import specifiers from source text. + * Supports both plain and named (`from`) import forms. + * + * @param soliditySource - The Solidity source code to parse. + * @returns An array of import specifier strings (e.g., `"./Foo.sol"`). + */ +export function parseSolidityImports(soliditySource: string): string[] { + const imports: string[] = []; + const re = /^\s*import\s+(?:[^'"]+from\s+)?["']([^"']+)["'];/gm; + let m: RegExpExecArray | null; + while ((m = re.exec(soliditySource)) !== null) { + imports.push(m[1]); + } + return imports; +} + +/** + * Removes block and line comments from Solidity source text. + * + * @param source - The raw Solidity source code. + * @returns The source with all comments stripped. + */ +export function removeSolidityComments(source: string): string { + return source + .replace(/\/\*[\s\S]*?\*\//g, "") + .replace(/\/\/.*$/gm, ""); +} + +/** + * Extracts the body of a named Solidity contract, ignoring braces in comments and strings. + * + * @param source - The full Solidity source code. + * @param contractName - The contract name to extract. + * @returns The contract body text (without outer braces), or `null` if not found. + */ +export function extractSolidityContractBody(source: string, contractName: string): string | null { + const declarationPattern = new RegExp( + `\\b(?:abstract\\s+)?contract\\s+${escapeRegExp(contractName)}\\b[^\\{]*\\{`, + ); + const declaration = declarationPattern.exec(source); + if (!declaration) { + return null; + } + + const openBraceIndex = declaration.index + declaration[0].lastIndexOf("{"); + const closeBraceIndex = findSolidityClosingBrace(source, openBraceIndex); + if (closeBraceIndex === -1) { + return null; + } + + return source.slice(openBraceIndex + 1, closeBraceIndex); +} + +/** + * Normalizes a single Solidity parameter type by removing data location and parameter name. + * For example, `uint256 memory data` becomes `uint256`. + * + * @param parameter - A raw parameter declaration string. + * @returns The normalized type string. + */ +export function normalizeSolidityParameterType(parameter: string): string { + const withoutName = parameter + .trim() + .replace(/\s+/g, " ") + .replace(/\b(calldata|memory|storage|indexed)\b/g, "") + .trim(); + + const parts = withoutName.split(" ").filter(Boolean); + if (parts.length <= 1) { + return withoutName; + } + + return parts.slice(0, -1).join(" "); +} + +/** + * Parses public and external Solidity functions with normalized signatures. + * + * @param source - The Solidity source code (comments are stripped internally). + * @returns An array of parsed function info objects. + */ +export function parseSolidityFunctions(source: string): SolidityFunctionInfo[] { + const cleanSource = removeSolidityComments(source); + const functions: SolidityFunctionInfo[] = []; + const functionPattern = /\bfunction\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)\s*([^;{]*)/g; + let match: RegExpExecArray | null; + + while ((match = functionPattern.exec(cleanSource)) !== null) { + const [, name, rawParameters, tail] = match; + const visibilityMatch = tail.match(/\b(external|public)\b/); + if (!visibilityMatch || name === "exportSelectors") { + continue; + } + + const parameterTypes = rawParameters + .split(",") + .map((parameter) => parameter.trim()) + .filter(Boolean) + .map(normalizeSolidityParameterType); + + functions.push({ + name, + signature: `${name}(${parameterTypes.join(",")})`, + visibility: visibilityMatch[1] as "external" | "public", + }); + } + + return functions; +} + +/** + * Parses function names exported through `this..selector` entries + * in the `exportSelectors` function body. + * + * @param source - The Solidity source code. + * @returns An array of exported function names. + */ +export function parseExportedSelectorNames(source: string): string[] { + const cleanSource = removeSolidityComments(source); + const exportMatch = cleanSource.match(/\bfunction\s+exportSelectors\s*\([^)]*\)[^{;]*\{([\s\S]*?)\n\s*\}/); + if (!exportMatch) { + return []; + } + + const exported = new Set(); + const selectorPattern = /\bthis\.([A-Za-z_][A-Za-z0-9_]*)\.selector\b/g; + let match: RegExpExecArray | null; + + while ((match = selectorPattern.exec(exportMatch[1])) !== null) { + exported.add(match[1]); + } + + return [...exported]; +} + +/** + * Parses canonical signatures exported through selector references and explicit keccak256 hashes + * in the `exportSelectors` function body. + * + * @param source - The Solidity source code. + * @param functions - The parsed function info array (used to resolve selector names to signatures). + * @returns An array of canonical signature strings (e.g., `"transfer(address,uint256)"`). + */ +export function parseExportedSelectorSignatures( + source: string, + functions: SolidityFunctionInfo[], +): string[] { + const cleanSource = removeSolidityComments(source); + const exportMatch = cleanSource.match(/\bfunction\s+exportSelectors\s*\([^)]*\)[^{;]*\{([\s\S]*?)\n\s*\}/); + if (!exportMatch) { + return []; + } + + const exported = new Set(); + const selectorPattern = /\bthis\.([A-Za-z_][A-Za-z0-9_]*)\.selector\b/g; + let match: RegExpExecArray | null; + + while ((match = selectorPattern.exec(exportMatch[1])) !== null) { + for (const fn of functions.filter((candidate) => candidate.name === match?.[1])) { + exported.add(fn.signature); + } + } + + const hashedSignaturePattern = /\bbytes4\s*\(\s*keccak256\s*\(\s*["']([^"']+)["']\s*\)\s*\)/g; + while ((match = hashedSignaturePattern.exec(exportMatch[1])) !== null) { + exported.add(match[1].replace(/\s+/g, "")); + } + + return [...exported]; +} + +/** + * Finds the matching closing brace index for an opening brace, skipping braces + * inside comments and string literals. + * + * @param source - The full Solidity source text. + * @param openBraceIndex - The index of the opening brace. + * @returns The index of the matching closing brace, or `-1` if unmatched. + */ +export function findSolidityClosingBrace(source: string, openBraceIndex: number): number { + let depth = 0; + let quote: '"' | "'" | null = null; + let inLineComment = false; + let inBlockComment = false; + + for (let index = openBraceIndex; index < source.length; index++) { + const current = source[index]; + const next = source[index + 1]; + + if (inLineComment) { + if (current === "\n") inLineComment = false; + continue; + } + if (inBlockComment) { + if (current === "*" && next === "/") { + inBlockComment = false; + index++; + } + continue; + } + if (quote) { + if (current === "\\") { + index++; + } else if (current === quote) { + quote = null; + } + continue; + } + if (current === "/" && next === "/") { + inLineComment = true; + index++; + continue; + } + if (current === "/" && next === "*") { + inBlockComment = true; + index++; + continue; + } + if (current === '"' || current === "'") { + quote = current; + continue; + } + if (current === "{") { + depth++; + } else if (current === "}") { + depth--; + if (depth === 0) return index; + } + } + + return -1; +} diff --git a/cli/src/utils/strings.ts b/cli/src/utils/strings.ts new file mode 100644 index 00000000..749a750c --- /dev/null +++ b/cli/src/utils/strings.ts @@ -0,0 +1,39 @@ +/** + * Converts a PascalCase or snake_case string to camelCase. + * + * @param value - The string to convert. + * @returns The camelCase version of the input, or an empty string if the result is empty. + */ +export function toCamelCase(value: string): string { + const words = value.match(/[A-Z]?[a-z0-9]+|[A-Z]+(?![a-z])/g) ?? [value]; + return words + .map((word) => word.toLowerCase()) + .map((word, index) => + index === 0 ? word : `${word.charAt(0).toUpperCase()}${word.slice(1)}`, + ) + .join(""); +} + +/** + * Deduplicates an array of strings, preserving first occurrence order. + * + * @param names - Array of strings that may contain duplicates. + * @returns A new array with only unique strings. + */ +export function uniqueStrings(names: string[]): string[] { + return [...new Set(names)]; +} + +/** + * Splits a comma-separated string into an array of trimmed, non-empty strings. + * + * @param value - The comma-separated string (or unknown value). + * @returns Array of trimmed, non-empty strings. + */ +export function splitCommaSeparated(value: unknown): string[] { + if (!value) return []; + return String(value) + .split(",") + .map((s) => s.trim()) + .filter(Boolean); +} diff --git a/cli/src/utils/terminal.ts b/cli/src/utils/terminal.ts new file mode 100644 index 00000000..f44a97e4 --- /dev/null +++ b/cli/src/utils/terminal.ts @@ -0,0 +1,79 @@ +/** + * Wraps terminal text in ANSI cyan color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in cyan escape sequences. + */ +export function cyan(text: string): string { + return `\u001b[36m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in ANSI red color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in red escape sequences. + */ +export function red(text: string): string { + return `\u001b[31m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in ANSI green color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in green escape sequences. + */ +export function green(text: string): string { + return `\u001b[32m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in ANSI yellow color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in yellow escape sequences. + */ +export function yellow(text: string): string { + return `\u001b[33m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in ANSI blue color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in blue escape sequences. + */ +export function blue(text: string): string { + return `\u001b[34m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in ANSI magenta color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in magenta escape sequences. + */ +export function magenta(text: string): string { + return `\u001b[35m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in ANSI white color codes. + * + * @param text - The text to colorize. + * @returns The text wrapped in white escape sequences. + */ +export function white(text: string): string { + return `\u001b[37m${text}\u001b[39m`; +} + +/** + * Wraps terminal text in an off-white color using 256-color mode. + * + * @param text - The text to colorize. + * @returns The text wrapped in dim escape sequences. + */ +export function dim(text: string): string { + return `\u001b[38;5;250m${text}\u001b[39m`; +} diff --git a/cli/test/fixtures/template-variants.snapshot.json b/cli/test/fixtures/template-variants.snapshot.json deleted file mode 100644 index 1ab0d33a..00000000 --- a/cli/test/fixtures/template-variants.snapshot.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "default": [ - "default-foundry", - "default-hardhat-minimal", - "default-hardhat-mocha-ethers", - "default-hardhat-node-runner-viem" - ] -} diff --git a/cli/test/integration/cliEntry.test.js b/cli/test/integration/cliEntry.test.js deleted file mode 100644 index 6d2116ee..00000000 --- a/cli/test/integration/cliEntry.test.js +++ /dev/null @@ -1,35 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const { spawnSync } = require("node:child_process"); - -const cliPath = path.join(__dirname, "..", "..", "index.js"); - -function runCli(args) { - return spawnSync(process.execPath, [cliPath, ...args], { - encoding: "utf8", - }); -} - -test("compose --version prints version and exits cleanly", () => { - const result = runCli(["--version"]); - const packageJson = require("../../package.json"); - - assert.equal(result.status, 0); - assert.equal(result.stdout.trim(), packageJson.version); -}); - -test("compose --help prints usage text", () => { - const result = runCli(["--help"]); - - assert.equal(result.status, 0); - assert.equal(result.stdout.includes("Usage:"), true); - assert.equal(result.stdout.includes("compose init [options]"), true); -}); - -test("compose unknown command exits with error", () => { - const result = runCli(["does-not-exist"]); - - assert.equal(result.status, 1); - assert.equal(result.stderr.includes("Unknown command"), true); -}); diff --git a/cli/test/integration/scaffoldVariants.test.js b/cli/test/integration/scaffoldVariants.test.js deleted file mode 100644 index eaf1ac53..00000000 --- a/cli/test/integration/scaffoldVariants.test.js +++ /dev/null @@ -1,147 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); -const { - loadTemplateConfig, - pickVariant, - resolveTemplatePath, -} = require("../../src/scaffold/utils/templateLoader"); -const { scaffold } = require("../../src/scaffold/scaffold"); - -async function scaffoldWithVariant(variant, options = {}) { - const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-it-")); - const originalCwd = process.cwd(); - process.chdir(tempRoot); - try { - const projectName = options.projectName || "demo-project"; - const result = await scaffold({ - projectName, - templatePath: resolveTemplatePath(variant), - options: { - framework: variant.framework, - language: variant.language, - hardhatProjectType: variant.projectType, - installDeps: false, - }, - }); - return { tempRoot, projectDir: result.projectDir, nextSteps: result.nextSteps }; - } finally { - process.chdir(originalCwd); - } -} - -test("scaffolds hardhat minimal variant", async () => { - const config = await loadTemplateConfig(); - const variant = pickVariant(config, { - template: "default", - framework: "hardhat", - language: "typescript", - projectType: "minimal", - }); - - const { projectDir, nextSteps } = await scaffoldWithVariant(variant, { - projectName: "hardhat-minimal-app", - }); - const packageJson = await fs.readJson(path.join(projectDir, "package.json")); - - assert.equal(await fs.pathExists(path.join(projectDir, "hardhat.config.ts")), true); - assert.equal(packageJson.name, "hardhat-minimal-app"); - assert.equal(nextSteps.includes("npm install"), true); -}); - -test("scaffolds hardhat mocha-ethers variant", async () => { - const config = await loadTemplateConfig(); - const variant = pickVariant(config, { - template: "default", - framework: "hardhat", - language: "typescript", - projectType: "mocha-ethers", - }); - - const { projectDir } = await scaffoldWithVariant(variant, { projectName: "hardhat-mocha-app" }); - const readme = await fs.readFile(path.join(projectDir, "README.md"), "utf8"); - - assert.equal(await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), true); - assert.equal(readme.includes("{{projectName}}"), false); - assert.equal(readme.includes("hardhat-mocha-app"), true); -}); - -test("scaffolds hardhat node-runner-viem variant", async () => { - const config = await loadTemplateConfig(); - const variant = pickVariant(config, { - template: "default", - framework: "hardhat", - language: "typescript", - projectType: "node-runner-viem", - }); - - const { projectDir } = await scaffoldWithVariant(variant, { - projectName: "hardhat-viem-app", - }); - const packageJson = await fs.readJson(path.join(projectDir, "package.json")); - - assert.equal(await fs.pathExists(path.join(projectDir, "test", "Counter.ts")), true); - assert.equal( - packageJson.dependencies["@perfect-abstractions/compose"], - "latest" - ); -}); - -test("scaffolds into current directory when projectName is dot and directory is logically empty", async () => { - const config = await loadTemplateConfig(); - const variant = pickVariant(config, { - template: "default", - framework: "hardhat", - language: "typescript", - projectType: "minimal", - }); - - const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-it-dot-")); - const originalCwd = process.cwd(); - process.chdir(tempRoot); - - try { - const result = await scaffold({ - projectName: ".", - templatePath: resolveTemplatePath(variant), - options: { - framework: variant.framework, - language: variant.language, - hardhatProjectType: variant.projectType, - installDeps: false, - }, - }); - - const packageJson = await fs.readJson(path.join(result.projectDir, "package.json")); - assert.equal(result.projectDir, tempRoot); - assert.equal(packageJson.name, path.basename(tempRoot)); - } finally { - process.chdir(originalCwd); - } -}); - -test("scaffold throws for unknown framework", async () => { - await assert.rejects( - () => - scaffold({ - projectName: "demo", - templatePath: resolveTemplatePath({ path: "templates/default/foundry" }), - options: { framework: "unknown", installDeps: false }, - }), - /Unknown framework/ - ); -}); - -test("scaffold throws when template path is missing", async () => { - await assert.rejects( - () => - scaffold({ - projectName: "demo", - templatePath: path.join(process.cwd(), "this-template-does-not-exist"), - options: { framework: "hardhat", language: "typescript", installDeps: false }, - }), - /Template path does not exist/ - ); -}); diff --git a/cli/test/unit/errors.test.js b/cli/test/unit/errors.test.js deleted file mode 100644 index c3d4250a..00000000 --- a/cli/test/unit/errors.test.js +++ /dev/null @@ -1,71 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { normalizeError, exitWithError } = require("../../src/utils/errors"); -const { logger } = require("../../src/utils/logger"); - -test("normalizeError returns original Error instance", () => { - const error = new Error("boom"); - assert.equal(normalizeError(error), error); -}); - -test("normalizeError wraps non-error values", () => { - const normalized = normalizeError("boom"); - assert.equal(normalized instanceof Error, true); - assert.equal(normalized.message, "boom"); -}); - -test("exitWithError logs error and sets process.exitCode", () => { - const calls = []; - const originalError = logger.error; - const originalPlain = logger.plain; - const originalExitCode = process.exitCode; - let exitCodeAfterCall; - - logger.error = (message) => calls.push(["error", message]); - logger.plain = (message) => calls.push(["plain", message]); - delete process.env.DEBUG; - process.exitCode = 0; - - try { - exitWithError("failure"); - exitCodeAfterCall = process.exitCode; - } finally { - logger.error = originalError; - logger.plain = originalPlain; - process.exitCode = originalExitCode; - } - - assert.deepEqual(calls, [["error", "failure"]]); - assert.equal(exitCodeAfterCall, 1); -}); - -test("exitWithError logs stack trace when DEBUG=1", () => { - const calls = []; - const originalError = logger.error; - const originalPlain = logger.plain; - const originalDebug = process.env.DEBUG; - const originalExitCode = process.exitCode; - let exitCodeAfterCall; - - logger.error = (message) => calls.push(["error", message]); - logger.plain = (message) => calls.push(["plain", message]); - process.env.DEBUG = "1"; - process.exitCode = 0; - - try { - exitWithError(new Error("debug-failure")); - exitCodeAfterCall = process.exitCode; - } finally { - logger.error = originalError; - logger.plain = originalPlain; - process.env.DEBUG = originalDebug; - process.exitCode = originalExitCode; - } - - assert.equal(calls[0][0], "error"); - assert.equal(calls[0][1], "debug-failure"); - assert.equal(calls[1][0], "plain"); - assert.equal(typeof calls[1][1], "string"); - assert.equal(calls[1][1].includes("debug-failure"), true); - assert.equal(exitCodeAfterCall, 1); -}); diff --git a/cli/test/unit/fileManager.test.js b/cli/test/unit/fileManager.test.js deleted file mode 100644 index 37f29fcd..00000000 --- a/cli/test/unit/fileManager.test.js +++ /dev/null @@ -1,71 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); -const { - assertTargetDoesNotExist, - appendLineIfMissing, - assertDirectoryEmpty, - getProjectDisplayName, - getTemplateDisplayName, -} = require("../../src/scaffold/utils/fileManager"); - -test("assertTargetDoesNotExist throws when path already exists", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-")); - await assert.rejects(() => assertTargetDoesNotExist(tempDir), /Target directory already exists/); -}); - -test("appendLineIfMissing creates file and avoids duplicate lines", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-")); - const filePath = path.join(tempDir, ".gitignore"); - - await appendLineIfMissing(filePath, "node_modules"); - await appendLineIfMissing(filePath, "node_modules"); - await appendLineIfMissing(filePath, "dist"); - - const content = await fs.readFile(filePath, "utf8"); - assert.equal(content, "node_modules\ndist\n"); -}); - -test("getTemplateDisplayName returns relative template path when inside templates root", () => { - const templatePath = path.join(process.cwd(), "src", "templates", "default", "foundry"); - assert.equal(getTemplateDisplayName(templatePath), "default/foundry"); -}); - -test("getTemplateDisplayName falls back to basename for external paths", () => { - const templatePath = path.join(os.tmpdir(), "custom-template"); - assert.equal(getTemplateDisplayName(templatePath), "custom-template"); -}); - -test("assertDirectoryEmpty allows only .git in directory", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-fm-empty-")); - - // Empty directory is allowed - await assert.doesNotReject(() => assertDirectoryEmpty(tempDir)); - - // Directory with only .git is allowed - const gitDir = path.join(tempDir, ".git"); - await fs.mkdir(gitDir); - await assert.doesNotReject(() => assertDirectoryEmpty(tempDir)); - - // Any additional entry should cause a failure - const readmePath = path.join(tempDir, "README.md"); - await fs.writeFile(readmePath, "# demo\n"); - await assert.rejects( - () => assertDirectoryEmpty(tempDir), - /Target directory is not empty/ - ); -}); - -test("getProjectDisplayName uses folder name for dot project", () => { - const projectDir = path.join(os.tmpdir(), "compose-cli-project-dir"); - const name = getProjectDisplayName(".", projectDir); - assert.equal(name, path.basename(projectDir)); -}); - -test("getProjectDisplayName returns projectName for non-dot project", () => { - const projectDir = path.join(os.tmpdir(), "compose-cli-project-dir"); - const name = getProjectDisplayName("my-app", projectDir); - assert.equal(name, "my-app"); -}); diff --git a/cli/test/unit/initOptions.test.js b/cli/test/unit/initOptions.test.js deleted file mode 100644 index ae338ee4..00000000 --- a/cli/test/unit/initOptions.test.js +++ /dev/null @@ -1,34 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { normalizeInitOptions } = require("../../src/commands/init"); - -test("normalizeInitOptions sets defaults", () => { - const options = normalizeInitOptions({}); - - assert.equal(options.template, ""); - assert.equal(options.framework, ""); - assert.equal(options.installDeps, undefined); -}); - -test("normalizeInitOptions prioritizes explicit flags", () => { - const options = normalizeInitOptions({ - name: "demo", - template: "default", - framework: "hardhat", - language: "javascript", - "install-deps": true, - }); - - assert.equal(options.projectName, "demo"); - assert.equal(options.framework, "hardhat"); - assert.equal(options.language, "javascript"); - assert.equal(options.installDeps, true); -}); - -test("normalizeInitOptions preserves no-install flag", () => { - const options = normalizeInitOptions({ - "install-deps": false, - }); - - assert.equal(options.installDeps, false); -}); diff --git a/cli/test/unit/initPrompts.test.js b/cli/test/unit/initPrompts.test.js deleted file mode 100644 index f9a8486e..00000000 --- a/cli/test/unit/initPrompts.test.js +++ /dev/null @@ -1,49 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); - -const { assertDirectoryEmpty } = require("../../src/scaffold/utils/fileManager"); -const { validateProjectLocation } = require("../../src/utils/prompts/initUtils"); - -test("validateProjectLocation returns true for non-dot names", async () => { - const result = await validateProjectLocation("my-app"); - assert.equal(result, true); -}); - -test("validateProjectLocation accepts dot in logically empty directory", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-init-")); - const originalCwd = process.cwd(); - process.chdir(tempDir); - - try { - // Ensure our invariant helper agrees this directory is acceptable - await assertDirectoryEmpty(process.cwd()); - - const result = await validateProjectLocation("."); - assert.equal(result, true); - } finally { - process.chdir(originalCwd); - } -}); - -test("validateProjectLocation rejects dot in non-empty directory", async () => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-init-")); - const originalCwd = process.cwd(); - process.chdir(tempDir); - - try { - const readmePath = path.join(tempDir, "README.md"); - await fs.writeFile(readmePath, "# demo\n"); - - const result = await validateProjectLocation("."); - assert.equal( - result, - 'Current directory must be empty (or only .git) when using ".".' - ); - } finally { - process.chdir(originalCwd); - } -}); - diff --git a/cli/test/unit/packageOrderer.test.js b/cli/test/unit/packageOrderer.test.js deleted file mode 100644 index 90d996f7..00000000 --- a/cli/test/unit/packageOrderer.test.js +++ /dev/null @@ -1,30 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { orderPackageJsonWithDepsBeforeDevDeps } = require("../../src/scaffold/utils/packageOrderer"); - -test("places dependencies before devDependencies", () => { - const input = { - name: "demo", - version: "1.0.0", - devDependencies: { b: "1.0.0" }, - dependencies: { a: "1.0.0" }, - scripts: { test: "node --test" }, - }; - - const ordered = orderPackageJsonWithDepsBeforeDevDeps(input); - assert.deepEqual(Object.keys(ordered), [ - "name", - "version", - "dependencies", - "devDependencies", - "scripts", - ]); -}); - -test("adds missing dependency blocks when absent", () => { - const ordered = orderPackageJsonWithDepsBeforeDevDeps({ name: "demo" }); - - assert.deepEqual(Object.keys(ordered), ["name", "dependencies", "devDependencies"]); - assert.deepEqual(ordered.dependencies, {}); - assert.deepEqual(ordered.devDependencies, {}); -}); diff --git a/cli/test/unit/templateLoader.test.js b/cli/test/unit/templateLoader.test.js deleted file mode 100644 index 4ac52aab..00000000 --- a/cli/test/unit/templateLoader.test.js +++ /dev/null @@ -1,59 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { - loadTemplateConfig, - pickVariant, - resolveTemplatePath, -} = require("../../src/scaffold/utils/templateLoader"); - -test("pickVariant returns foundry variant", async () => { - const config = await loadTemplateConfig(); - const variant = pickVariant(config, { - template: "default", - framework: "foundry", - }); - - assert.equal(variant.id, "default-foundry"); -}); - -test("pickVariant returns hardhat minimal variant", async () => { - const config = await loadTemplateConfig(); - const variant = pickVariant(config, { - template: "default", - framework: "hardhat", - language: "typescript", - projectType: "minimal", - }); - - assert.equal(variant.id, "default-hardhat-minimal"); -}); - -test("pickVariant throws for unknown template", async () => { - const config = await loadTemplateConfig(); - assert.throws( - () => - pickVariant(config, { - template: "does-not-exist", - framework: "foundry", - }), - /Template not found/ - ); -}); - -test("pickVariant throws when no variant matches", async () => { - const config = await loadTemplateConfig(); - assert.throws( - () => - pickVariant(config, { - template: "default", - framework: "hardhat", - language: "javascript", - }), - /No template variant/ - ); -}); - -test("resolveTemplatePath returns an absolute path in src", () => { - const resolved = resolveTemplatePath({ path: "templates/default/foundry" }); - assert.equal(resolved.includes("/src/templates/default/foundry"), true); -}); diff --git a/cli/test/unit/templateSnapshot.test.js b/cli/test/unit/templateSnapshot.test.js deleted file mode 100644 index 483d3193..00000000 --- a/cli/test/unit/templateSnapshot.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const fs = require("fs-extra"); -const path = require("node:path"); -const { loadTemplateConfig } = require("../../src/scaffold/utils/templateLoader"); - -test("template variants match snapshot", async () => { - const snapshotPath = path.join(__dirname, "..", "fixtures", "template-variants.snapshot.json"); - const snapshot = await fs.readJson(snapshotPath); - const config = await loadTemplateConfig(); - - const actual = {}; - config.templates.forEach((template) => { - actual[template.id] = template.variants.map((variant) => variant.id); - }); - - assert.deepEqual(actual, snapshot); -}); diff --git a/cli/test/unit/tokenReplace.test.js b/cli/test/unit/tokenReplace.test.js deleted file mode 100644 index 1645af96..00000000 --- a/cli/test/unit/tokenReplace.test.js +++ /dev/null @@ -1,26 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const path = require("node:path"); -const os = require("node:os"); -const fs = require("fs-extra"); -const { replaceTokensRecursively } = require("../../src/scaffold/utils/tokenReplace"); - -test("replaceTokensRecursively updates supported text files recursively", async () => { - const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "compose-cli-tr-")); - const nestedDir = path.join(rootDir, "nested"); - await fs.ensureDir(nestedDir); - - const readmePath = path.join(rootDir, "README.md"); - const jsonPath = path.join(nestedDir, "package.json"); - const pngPath = path.join(rootDir, "image.png"); - - await fs.writeFile(readmePath, "Project {{projectName}}"); - await fs.writeFile(jsonPath, '{"name":"{{projectName}}"}'); - await fs.writeFile(pngPath, "binary-{{projectName}}"); - - await replaceTokensRecursively(rootDir, { "{{projectName}}": "demo-app" }); - - assert.equal(await fs.readFile(readmePath, "utf8"), "Project demo-app"); - assert.equal(await fs.readFile(jsonPath, "utf8"), '{"name":"demo-app"}'); - assert.equal(await fs.readFile(pngPath, "utf8"), "binary-{{projectName}}"); -}); diff --git a/cli/test/unit/validateTemplatesConfig.test.js b/cli/test/unit/validateTemplatesConfig.test.js deleted file mode 100644 index 9808ad2a..00000000 --- a/cli/test/unit/validateTemplatesConfig.test.js +++ /dev/null @@ -1,19 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const templatesConfig = require("../../src/config/templates.json"); -const { validateTemplatesConfig } = require("../../src/config/validateTemplatesConfig"); - -test("validateTemplatesConfig accepts current registry", () => { - assert.equal(validateTemplatesConfig(templatesConfig), true); -}); - -test("validateTemplatesConfig rejects missing variants", () => { - assert.throws( - () => - validateTemplatesConfig({ - templates: [{ id: "default", name: "Default", variants: [] }], - defaultTemplateId: "default", - }), - /variants must be a non-empty array/ - ); -}); diff --git a/cli/test/unit/versionCommand.test.js b/cli/test/unit/versionCommand.test.js deleted file mode 100644 index 629545e6..00000000 --- a/cli/test/unit/versionCommand.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const test = require("node:test"); -const assert = require("node:assert/strict"); -const { runVersionCommand } = require("../../src/commands/version"); -const { logger } = require("../../src/utils/logger"); - -test("runVersionCommand prints version string", () => { - const calls = []; - const originalPlain = logger.plain; - logger.plain = (message) => calls.push(message); - - try { - runVersionCommand("1.2.3"); - } finally { - logger.plain = originalPlain; - } - - assert.deepEqual(calls, ["1.2.3"]); -}); diff --git a/cli/tsconfig.json b/cli/tsconfig.json new file mode 100644 index 00000000..58bc351d --- /dev/null +++ b/cli/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "types": ["node"], + "strict": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"], + "exclude": ["src/templates"] +} diff --git a/package-lock.json b/package-lock.json index 6af5d0ea..4688bf8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,76 +22,32 @@ }, "cli": { "name": "@perfect-abstractions/compose-cli", - "version": "0.0.5", + "version": "0.1.0", "license": "MIT", "dependencies": { + "@inquirer/prompts": "^8.5.2", + "@perfect-abstractions/compose": "0.0.4", + "commander": "^13.1.0", "fs-extra": "^11.3.3", "inquirer": "^13.3.0", - "minimist": "^1.2.8", - "picocolors": "^1.1.1" + "picocolors": "^1.1.1", + "viem": "^2.52.2" }, "bin": { "compose": "bin/compose.js" }, "devDependencies": { "@eslint/js": "^10.0.1", - "@nomicfoundation/hardhat-ethers": "^4.0.5", - "@nomicfoundation/hardhat-ignition": "^3.0.8", - "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.3", - "@nomicfoundation/hardhat-toolbox-viem": "^5.0.2", - "@types/chai": "^5.2.3", - "@types/chai-as-promised": "^8.0.2", - "@types/mocha": "^10.0.10", "@types/node": "^22.19.13", - "chai": "^6.2.2", "eslint": "^10.1.0", - "ethers": "^6.16.0", - "forge-std": "github:foundry-rs/forge-std#v1.9.4", - "hardhat": "^3.1.10", - "mocha": "^11.7.5", + "tsx": "^4.19.1", "typescript": "~5.8.0", - "viem": "^2.47.0" + "typescript-eslint": "^8.0.0" }, "engines": { "node": ">=20" } }, - "cli/node_modules/@actions/core": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@actions/exec": "^1.1.1", - "@actions/http-client": "^2.0.1" - } - }, - "cli/node_modules/@actions/exec": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@actions/io": "^1.0.1" - } - }, - "cli/node_modules/@actions/http-client": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "tunnel": "^0.0.6", - "undici": "^5.25.4" - } - }, - "cli/node_modules/@actions/io": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "dev": true, - "license": "MIT" - }, "cli/node_modules/@esbuild/linux-x64": { "version": "0.27.3", "cpu": [ @@ -107,7564 +63,4256 @@ "node": ">=18" } }, - "cli/node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", + "cli/node_modules/@eslint/js": { + "version": "10.0.1", "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "cli/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "cli/node_modules/@types/node": { + "version": "22.19.13", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" } }, - "cli/node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "dev": true, + "cli/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "license": "MIT", "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "cli/node_modules/@eslint/config-array": { - "version": "0.23.3", + "cli/node_modules/esbuild": { + "version": "0.27.3", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.3", - "debug": "^4.3.1", - "minimatch": "^10.2.4" + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, - "cli/node_modules/@eslint/config-helpers": { - "version": "0.5.3", - "dev": true, - "license": "Apache-2.0", + "cli/node_modules/fs-extra": { + "version": "11.3.3", + "license": "MIT", "dependencies": { - "@eslint/core": "^1.1.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=14.14" } }, - "cli/node_modules/@eslint/core": { - "version": "1.1.1", + "cli/node_modules/get-tsconfig": { + "version": "4.13.6", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.15" + "resolve-pkg-maps": "^1.0.0" }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "cli/node_modules/@eslint/js": { - "version": "10.0.1", - "dev": true, + "cli/node_modules/inquirer": { + "version": "13.3.0", "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "dependencies": { + "@inquirer/ansi": "^2.0.3", + "@inquirer/core": "^11.1.5", + "@inquirer/prompts": "^8.3.0", + "@inquirer/type": "^4.0.3", + "mute-stream": "^3.0.0", + "run-async": "^4.0.6", + "rxjs": "^7.8.2" }, - "funding": { - "url": "https://eslint.org/donate" + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { - "eslint": "^10.0.0" + "@types/node": ">=18" }, "peerDependenciesMeta": { - "eslint": { + "@types/node": { "optional": true } } }, - "cli/node_modules/@eslint/object-schema": { - "version": "3.0.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "cli/node_modules/@eslint/plugin-kit": { - "version": "0.6.1", - "dev": true, - "license": "Apache-2.0", + "cli/node_modules/jsonfile": { + "version": "6.2.0", + "license": "MIT", "dependencies": { - "@eslint/core": "^1.1.1", - "levn": "^0.4.1" + "universalify": "^2.0.0" }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "cli/node_modules/@ethersproject/abi": { - "version": "5.8.0", + "cli/node_modules/resolve-pkg-maps": { + "version": "1.0.0", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "license": "MIT", - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "cli/node_modules/@ethersproject/abstract-provider": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "cli/node_modules/run-async": { + "version": "4.0.6", "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0" + "engines": { + "node": ">=0.12.0" } }, - "cli/node_modules/@ethersproject/abstract-signer": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", + "cli/node_modules/rxjs": { + "version": "7.8.2", + "license": "Apache-2.0", "dependencies": { - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0" + "tslib": "^2.1.0" } }, - "cli/node_modules/@ethersproject/address": { - "version": "5.8.0", + "cli/node_modules/tsx": { + "version": "4.21.0", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/rlp": "^5.8.0" + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "cli/node_modules/@ethersproject/base64": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "cli/node_modules/undici-types": { + "version": "6.21.0", + "devOptional": true, + "license": "MIT" + }, + "cli/node_modules/universalify": { + "version": "2.0.1", "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0" + "engines": { + "node": ">= 10.0.0" } }, - "cli/node_modules/@ethersproject/bignumber": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "bn.js": "^5.2.1" - } + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" }, - "cli/node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/abtesting": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.21.1.tgz", + "integrity": "sha512-Wia5/mNTfiU0PIUN25UMfAGGdASkkwuCS9nBAdmhqrNPY/ff7U/6MgBVdwFDPsa3sA1msutPtO50gvOzx6MOXA==", "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.8.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/constants": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/autocomplete-core": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.9.tgz", + "integrity": "sha512-4U2JKLMWlDu0CotYyUkWakDxr8AIav3QtIUXXRpfavYN29aVWfzlwJp9T0rPKEf/dO2QCPAUc0Kq1Tj1GJxo2A==", "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.8.0" + "@algolia/autocomplete-plugin-algolia-insights": "1.19.9", + "@algolia/autocomplete-shared": "1.19.9" } }, - "cli/node_modules/@ethersproject/hash": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.9.tgz", + "integrity": "sha512-6mExC6X7762s2SV3eJy3QOkB8bdMmnUhQ2agvGVDuzwoGyr3PquGSY/0vPQXCfiAiCaXUz1rXn+lwghgSi0l0w==", "license": "MIT", "dependencies": { - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" + "@algolia/autocomplete-shared": "1.19.9" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" } }, - "cli/node_modules/@ethersproject/keccak256": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/autocomplete-shared": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.9.tgz", + "integrity": "sha512-YosP9Uoek6y/Ur1r1qeogk4biMe/hzkyNcgMCciw0//3XpCM7VlYLSHnyt/vOnEOGhCCc0+3v+unEiH6zz+Z1A==", "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "js-sha3": "0.8.0" + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, - "cli/node_modules/@ethersproject/logger": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT" - }, - "cli/node_modules/@ethersproject/networks": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-abtesting": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.55.1.tgz", + "integrity": "sha512-miW8RzAtBgNiEJ9fGEhsOPgWUpekAe64YcVufqXrlykj0Jjmo5nj0a5f/HAzRVX5ZuU1GAVd7BkzFDx7q50P3A==", "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.8.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/properties": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-analytics": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.55.1.tgz", + "integrity": "sha512-eR3J3kB9JX6DdCvDRi3I4KPfwO6fR9HWYRXhVke2TXIoOQafMKCRAneg33JRmIrb+DnnJ/eWApJLF1O1CLPERg==", "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.8.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/rlp": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0" + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/signing-key": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-insights": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.55.1.tgz", + "integrity": "sha512-OVtj9uA//+pjvKQI5INnzbyLrf3ClNv3XRbWswwJ2kHIStQNHtBfHo+LofNB/WhM9xjuXlW5ANn2aMj65UGx7w==", "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "bn.js": "^5.2.1", - "elliptic": "6.6.1", - "hash.js": "1.1.7" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/strings": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-personalization": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.55.1.tgz", + "integrity": "sha512-oKlVFlp+qbIEe4p7E54zSiP2gEV/vDu972Ykv8VDMFwEvreS7m0YKA3a8hGGHwc7yiBUGGiR3LlwzMLfnJmy6Q==", "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/transactions": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-query-suggestions": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.55.1.tgz", + "integrity": "sha512-BOVrld6vdtsFmotVDMTVQfYXwrVplJ+DUvy60JFi+tkWV698q2J9NNPKEO3dr5qxtSLKQP4vHF8n+3U5PDWhOQ==", "license": "MIT", "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "cli/node_modules/@ethersproject/web": { - "version": "5.8.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@algolia/client-search": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.55.1.tgz", + "integrity": "sha512-GAqHl9zERhC3bbBfubwUu07G3UXO06gORvOcsiTBZB3et0s3auNUbHlYdYNp4VKa3sUZqH5AcD3OKzU/KDGXjQ==", "license": "MIT", + "peer": true, "dependencies": { - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "cli/node_modules/@fastify/busboy": { - "version": "2.1.1", - "dev": true, - "license": "MIT", + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, "engines": { - "node": ">=14" + "node": ">= 14.0.0" } }, - "cli/node_modules/@humanfs/core": { - "version": "0.19.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", + "license": "MIT" }, - "cli/node_modules/@humanfs/node": { - "version": "0.16.7", - "dev": true, - "license": "Apache-2.0", + "node_modules/@algolia/ingestion": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.55.1.tgz", + "integrity": "sha512-BXZw+C+gsWL7pZvbnhJUnCXASiDLGcQxVV7h55Pyh2DmSzwdZIVccE5xc9RVD2trtrhIqk5smuODTxtaZqd0IA==", + "license": "MIT", "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" }, "engines": { - "node": ">=18.18.0" + "node": ">= 14.0.0" } }, - "cli/node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "cli/node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "cli/node_modules/@inquirer/ansi": { - "version": "2.0.3", + "node_modules/@algolia/monitoring": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.55.1.tgz", + "integrity": "sha512-9g/ceZrZTqA62FA3588Xj0onRPjDNfu0pVQqefK0rrHp9H6Wblph/YmzGjZ2g8uqbTh0ZGIvAGCzErU8f7MHpA==", "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">= 14.0.0" } }, - "cli/node_modules/@inquirer/checkbox": { - "version": "5.1.0", + "node_modules/@algolia/recommend": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.55.1.tgz", + "integrity": "sha512-cZTIrGyAP+W4A6jDVwvWM/JOaoJKQkD/2a5eLUEeNdKAD45jN7BCpsMDONyhZlosLa4UwL8uiINQzj4iFy9nqg==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.3", - "@inquirer/core": "^11.1.5", - "@inquirer/figures": "^2.0.3", - "@inquirer/type": "^4.0.3" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">= 14.0.0" } }, - "cli/node_modules/@inquirer/confirm": { - "version": "6.0.8", + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.55.1.tgz", + "integrity": "sha512-N6I3leW0UO8Y9Zv90yo2UHgYGuxZO0mjbvzNxDIJDjO0qECEF7Z9XMvSNeUWXQh/iNDA9lr8MfEy3rmZGIcclw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/type": "^4.0.3" + "@algolia/client-common": "5.55.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">= 14.0.0" } }, - "cli/node_modules/@inquirer/core": { - "version": "11.1.5", + "node_modules/@algolia/requester-fetch": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.55.1.tgz", + "integrity": "sha512-ukU5zeeFs44rQkzv+TRdYard+d+3lmPGs8lPZhHtWE8rfz+LlBSF6s9kP3VQ7LeOYL8Dz0u6tZfnyTrqrumbHQ==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.3", - "@inquirer/figures": "^2.0.3", - "@inquirer/type": "^4.0.3", - "cli-width": "^4.1.0", - "fast-wrap-ansi": "^0.2.0", - "mute-stream": "^3.0.0", - "signal-exit": "^4.1.0" + "@algolia/client-common": "5.55.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">= 14.0.0" } }, - "cli/node_modules/@inquirer/editor": { - "version": "5.0.8", + "node_modules/@algolia/requester-node-http": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.55.1.tgz", + "integrity": "sha512-lCwXyijwPm3vbYHpBXPRomMcD6mgiptmps27gnMCf4HK+u/AOeFPBnIFh4V3l4A5SnP9VRiKBZqwGBpUH0vaTg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/external-editor": "^2.0.3", - "@inquirer/type": "^4.0.3" + "@algolia/client-common": "5.55.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">= 14.0.0" } }, - "cli/node_modules/@inquirer/expand": { - "version": "5.0.8", + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/type": "^4.0.3" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "cli/node_modules/@inquirer/external-editor": { - "version": "2.0.3", + "node_modules/@antfu/install-pkg/node_modules/package-manager-detector": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.7.0.tgz", + "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==", + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.2" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=6.9.0" } }, - "cli/node_modules/@inquirer/figures": { - "version": "2.0.3", + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=6.9.0" } }, - "cli/node_modules/@inquirer/input": { - "version": "5.0.8", + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "license": "MIT", + "peer": true, "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/type": "^4.0.3" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "cli/node_modules/@inquirer/number": { - "version": "4.0.8", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/type": "^4.0.3" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "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==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "cli/node_modules/@inquirer/password": { - "version": "5.0.8", + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.3", - "@inquirer/core": "^11.1.5", - "@inquirer/type": "^4.0.3" + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=6.9.0" } }, - "cli/node_modules/@inquirer/prompts": { - "version": "8.3.0", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^5.1.0", - "@inquirer/confirm": "^6.0.8", - "@inquirer/editor": "^5.0.8", - "@inquirer/expand": "^5.0.8", - "@inquirer/input": "^5.0.8", - "@inquirer/number": "^4.0.8", - "@inquirer/password": "^5.0.8", - "@inquirer/rawlist": "^5.2.4", - "@inquirer/search": "^4.1.4", - "@inquirer/select": "^5.1.0" + "@babel/types": "^7.29.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=6.9.0" } }, - "cli/node_modules/@inquirer/rawlist": { - "version": "5.2.4", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/type": "^4.0.3" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "engines": { + "node": ">=6.9.0" } }, - "cli/node_modules/@inquirer/search": { - "version": "4.1.4", + "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==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.5", - "@inquirer/figures": "^2.0.3", - "@inquirer/type": "^4.0.3" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=6.9.0" }, "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@inquirer/select": { - "version": "5.1.0", + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.3", - "@inquirer/core": "^11.1.5", - "@inquirer/figures": "^2.0.3", - "@inquirer/type": "^4.0.3" + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=6.9.0" }, "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@inquirer/type": { - "version": "4.0.3", + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" }, "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "cli/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "cli/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "dev": true, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=6.9.0" } }, - "cli/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "dev": true, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.2.2" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=6.9.0" } }, - "cli/node_modules/@noble/ciphers": { - "version": "1.2.1", - "dev": true, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">=6.9.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@noble/curves": { - "version": "1.4.2", - "dev": true, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", "license": "MIT", "dependencies": { - "@noble/hashes": "1.4.0" + "@babel/types": "^7.29.7" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=6.9.0" } }, - "cli/node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "license": "MIT", "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=6.9.0" } }, - "cli/node_modules/@noble/hashes": { - "version": "1.7.1", - "dev": true, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">=6.9.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/edr": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", "license": "MIT", "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.24", - "@nomicfoundation/edr-darwin-x64": "0.12.0-next.24", - "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.24", - "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.24", - "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.24", - "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.24", - "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.24" + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { - "node": ">= 20" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, "engines": { - "node": ">= 20" + "node": ">=6.9.0" } }, - "cli/node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { - "node": ">= 20" + "node": ">=6.9.0" } }, - "cli/node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { - "node": ">= 20" + "node": ">=6.9.0" } }, - "cli/node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", "engines": { - "node": ">= 20" + "node": ">=6.9.0" } }, - "cli/node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, "engines": { - "node": ">= 20" + "node": ">=6.9.0" } }, - "cli/node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, "engines": { - "node": ">= 20" + "node": ">=6.9.0" } }, - "cli/node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.12.0-next.24", - "dev": true, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">= 20" + "node": ">=6.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-errors": { - "version": "3.0.7", - "dev": true, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", "license": "MIT", "dependencies": { - "@nomicfoundation/hardhat-utils": "^4.0.0" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-ethers": { - "version": "4.0.5", - "dev": true, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "debug": "^4.3.2", - "ethereum-cryptography": "^2.2.1", - "ethers": "^6.14.0" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "hardhat": "^3.0.7" + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-ethers-chai-matchers": { - "version": "3.0.3", - "dev": true, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@types/chai-as-promised": "^8.0.1", - "chai-as-promised": "^8.0.0", - "deep-eql": "^5.0.1" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^4.0.0", - "chai": ">=5.1.2 <7", - "ethers": "^6.14.0", - "hardhat": "^3.0.0" + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-ignition": { - "version": "3.0.8", - "dev": true, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/ignition-core": "^3.0.8", - "@nomicfoundation/ignition-ui": "^3.0.8", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "json5": "^2.2.3", - "prompts": "^2.4.2" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@nomicfoundation/hardhat-verify": "^3.0.0", - "hardhat": "^3.1.5" + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-ignition-ethers": { - "version": "3.0.8", - "dev": true, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^4.0.0", - "@nomicfoundation/hardhat-ignition": "^3.0.7", - "@nomicfoundation/hardhat-verify": "^3.0.0", - "@nomicfoundation/ignition-core": "^3.0.7", - "ethers": "^6.14.0", - "hardhat": "^3.1.5" + "@babel/core": "^7.13.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-ignition-viem": { - "version": "3.0.8", - "dev": true, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@nomicfoundation/hardhat-ignition": "^3.0.7", - "@nomicfoundation/hardhat-verify": "^3.0.0", - "@nomicfoundation/hardhat-viem": "^3.0.2", - "@nomicfoundation/ignition-core": "^3.0.7", - "hardhat": "^3.1.5", - "viem": "^2.43.0" + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-keystore": { - "version": "3.0.5", - "dev": true, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "license": "MIT", - "peer": true, - "dependencies": { - "@noble/ciphers": "1.2.1", - "@noble/hashes": "1.7.1", - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/hardhat-zod-utils": "^3.0.2", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "zod": "^3.23.8" + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "hardhat": "^3.0.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-mocha": { - "version": "3.0.11", - "dev": true, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/hardhat-zod-utils": "^3.0.2", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "tsx": "^4.19.3", - "zod": "^3.23.8" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "hardhat": "^3.0.12", - "mocha": "^11.0.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "3.0.4", - "dev": true, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "hardhat": "^3.0.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-node-test-reporter": { - "version": "3.0.2", - "dev": true, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "license": "MIT", "dependencies": { - "@actions/core": "^1.10.1", - "chalk": "^5.3.0", - "jest-diff": "^29.7.0" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-node-test-runner": { - "version": "3.0.9", - "dev": true, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-node-test-reporter": "^3.0.2", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/hardhat-zod-utils": "^3.0.2", - "tsx": "^4.19.3", - "zod": "^3.23.8" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "hardhat": "^3.0.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-toolbox-mocha-ethers": { - "version": "3.0.3", - "dev": true, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^4.0.0", - "@nomicfoundation/hardhat-ethers-chai-matchers": "^3.0.0", - "@nomicfoundation/hardhat-ignition": "^3.0.0", - "@nomicfoundation/hardhat-ignition-ethers": "^3.0.0", - "@nomicfoundation/hardhat-keystore": "^3.0.0", - "@nomicfoundation/hardhat-mocha": "^3.0.0", - "@nomicfoundation/hardhat-network-helpers": "^3.0.0", - "@nomicfoundation/hardhat-typechain": "^3.0.0", - "@nomicfoundation/hardhat-verify": "^3.0.0", - "@nomicfoundation/ignition-core": "^3.0.0", - "chai": ">=5.1.2 <7", - "ethers": "^6.14.0", - "hardhat": "^3.0.0", - "mocha": "^11.0.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-toolbox-viem": { - "version": "5.0.2", - "dev": true, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { - "@nomicfoundation/hardhat-ignition": "^3.0.7", - "@nomicfoundation/hardhat-ignition-viem": "^3.0.7", - "@nomicfoundation/hardhat-keystore": "^3.0.0", - "@nomicfoundation/hardhat-network-helpers": "^3.0.0", - "@nomicfoundation/hardhat-node-test-runner": "^3.0.0", - "@nomicfoundation/hardhat-verify": "^3.0.0", - "@nomicfoundation/hardhat-viem": "^3.0.2", - "@nomicfoundation/hardhat-viem-assertions": "^3.0.5", - "@nomicfoundation/ignition-core": "^3.0.7", - "hardhat": "^3.0.0", - "viem": "^2.43.0" + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/hardhat-typechain": { - "version": "3.0.3", - "dev": true, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/hardhat-zod-utils": "^3.0.2", - "@typechain/ethers-v6": "^0.5.0", - "debug": "^4.3.2", - "typechain": "^8.3.1", - "zod": "^3.23.8" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@nomicfoundation/hardhat-ethers": "^4.0.0", - "ethers": "^6.14.0", - "hardhat": "^3.1.6" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-utils": { - "version": "4.0.0", - "dev": true, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", "license": "MIT", "dependencies": { - "@streamparser/json-node": "^0.0.22", - "debug": "^4.3.2", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^2.2.1", - "fast-equals": "^5.4.0", - "json-stream-stringify": "^3.1.6", - "rfdc": "^1.3.1", - "undici": "^6.16.1" - } - }, - "cli/node_modules/@nomicfoundation/hardhat-utils/node_modules/undici": { - "version": "6.23.0", - "dev": true, - "license": "MIT", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": ">=18.17" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-vendored": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@nomicfoundation/hardhat-verify": { - "version": "3.0.11", - "dev": true, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", "license": "MIT", - "peer": true, "dependencies": { - "@ethersproject/abi": "^5.8.0", - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/hardhat-zod-utils": "^3.0.2", - "cbor2": "^1.9.0", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "semver": "^7.6.3", - "zod": "^3.23.8" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "hardhat": "^3.1.6" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-viem": { - "version": "3.0.3", - "dev": true, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "hardhat": "^3.0.0", - "viem": "^2.43.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-viem-assertions": { - "version": "3.0.6", - "dev": true, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@nomicfoundation/hardhat-viem": "^3.0.2", - "hardhat": "^3.0.0", - "viem": "^2.43.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/hardhat-zod-utils": { - "version": "3.0.2", - "dev": true, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", "license": "MIT", "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "zod": "^3.23.8" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/ignition-core": { - "version": "3.0.8", - "dev": true, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", "license": "MIT", - "peer": true, "dependencies": { - "@ethersproject/address": "5.6.1", - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/solidity-analyzer": "^0.1.1", - "cbor2": "^1.9.0", - "debug": "^4.3.2", - "ethers": "^6.14.0", - "immer": "10.0.2", - "lodash-es": "4.17.21", - "ndjson": "2.0.0" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "cli/node_modules/@nomicfoundation/ignition-core/node_modules/@ethersproject/address": { - "version": "5.6.1", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.6.2", - "@ethersproject/bytes": "^5.6.1", - "@ethersproject/keccak256": "^5.6.1", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.1" - } - }, - "cli/node_modules/@nomicfoundation/ignition-ui": { - "version": "3.0.8", - "dev": true - }, - "cli/node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.2", - "dev": true, - "license": "MIT", + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" }, - "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.2", - "dev": true, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", "license": "MIT", - "optional": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=14" - } - }, - "cli/node_modules/@scure/base": { - "version": "1.1.9", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@scure/bip32": { - "version": "1.4.0", - "dev": true, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", "license": "MIT", "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" + "@babel/helper-plugin-utils": "^7.29.7" }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "cli/node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, - "license": "MIT", "engines": { - "node": ">= 16" + "node": ">=6.9.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@scure/bip39": { - "version": "1.3.0", - "dev": true, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", "license": "MIT", "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": ">= 16" + "node": ">=6.9.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@sentry/core": { - "version": "9.47.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "cli/node_modules/@streamparser/json": { - "version": "0.0.22", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@streamparser/json-node": { - "version": "0.0.22", - "dev": true, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", "license": "MIT", "dependencies": { - "@streamparser/json": "^0.0.22" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@typechain/ethers-v6": { - "version": "0.5.1", - "dev": true, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", "license": "MIT", "dependencies": { - "lodash": "^4.17.15", - "ts-essentials": "^7.0.1" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "ethers": "6.x", - "typechain": "^8.3.2", - "typescript": ">=4.7.0" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@types/chai": { - "version": "5.2.3", - "dev": true, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", "license": "MIT", "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@types/chai-as-promised": { - "version": "8.0.2", - "dev": true, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", "license": "MIT", "dependencies": { - "@types/chai": "*" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/@types/deep-eql": { - "version": "4.0.2", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@types/esrecurse": { - "version": "4.3.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@types/mocha": { - "version": "10.0.10", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/@types/node": { - "version": "22.19.13", - "devOptional": true, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", "license": "MIT", - "peer": true, "dependencies": { - "undici-types": "~6.21.0" - } - }, - "cli/node_modules/@types/prettier": { - "version": "2.7.3", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/abitype": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3.22.0 || ^4.0.0" + "engines": { + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/adm-zip": { - "version": "0.4.16", - "dev": true, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=0.3.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/aes-js": { - "version": "4.0.0-beta.5", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/ajv": { - "version": "6.14.0", - "dev": true, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", "license": "MIT", "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" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "cli/node_modules/ansi-styles": { - "version": "5.2.0", - "dev": true, - "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/array-back": { - "version": "3.1.0", - "dev": true, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/assertion-error": { - "version": "2.0.1", - "dev": true, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/balanced-match": { - "version": "4.0.4", - "dev": true, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": "18 || 20 || >=22" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/bn.js": { - "version": "5.2.3", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/brace-expansion": { - "version": "5.0.4", - "dev": true, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": "18 || 20 || >=22" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/brorand": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/browser-stdout": { - "version": "1.3.1", - "dev": true, - "license": "ISC" - }, - "cli/node_modules/cbor2": { - "version": "1.12.0", - "dev": true, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=18.7" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/chai": { - "version": "6.2.2", - "dev": true, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", "license": "MIT", - "peer": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/chai-as-promised": { - "version": "8.0.2", - "dev": true, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", "license": "MIT", "dependencies": { - "check-error": "^2.1.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "chai": ">= 2.1.2 < 7" + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/chalk": { - "version": "5.6.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/check-error": { - "version": "2.1.3", - "dev": true, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, "engines": { - "node": ">= 16" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/chokidar": { - "version": "4.0.3", - "dev": true, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">= 14.16.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/cli-width": { - "version": "4.1.0", - "license": "ISC", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">= 12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/cliui": { - "version": "8.0.1", - "dev": true, - "license": "ISC", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "dev": true, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.29.7.tgz", + "integrity": "sha512-J0wGhKan+rIiE2OhfhRptySLrJ6SjQYM6b6N1FMlhyhCcw1Mig8vQjWchyB+bgHGDvaWo6Diu6CLRMra2uMtmg==", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz", + "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-args": { - "version": "5.2.1", - "dev": true, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz", + "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==", "license": "MIT", "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage": { - "version": "6.1.3", - "dev": true, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz", + "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==", "license": "MIT", "dependencies": { - "array-back": "^4.0.2", - "chalk": "^2.4.2", - "table-layout": "^1.0.2", - "typical": "^5.2.0" + "@babel/plugin-transform-react-jsx": "^7.29.7" }, "engines": { - "node": ">=8.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz", + "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==", "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage/node_modules/array-back": { - "version": "4.0.2", - "dev": true, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage/node_modules/chalk": { - "version": "2.4.2", - "dev": true, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/command-line-usage/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/command-line-usage/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz", + "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==", "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, "engines": { - "node": ">=0.8.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "cli/node_modules/command-line-usage/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/command-line-usage/node_modules/typical": { - "version": "5.2.0", - "dev": true, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, "engines": { - "node": ">=8" - } - }, - "cli/node_modules/decamelize": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "cli/node_modules/deep-eql": { - "version": "5.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "cli/node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/diff": { - "version": "7.0.0", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "cli/node_modules/diff-sequences": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/elliptic": { - "version": "6.6.1", - "dev": true, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", "license": "MIT", "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "cli/node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/env-paths": { - "version": "2.2.1", - "dev": true, - "license": "MIT", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/esbuild": { - "version": "0.27.3", - "dev": true, - "hasInstallScript": true, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=18" + "node": ">=6.9.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/eslint": { - "version": "10.1.0", - "dev": true, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", "license": "MIT", - "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.3", - "@eslint/config-helpers": "^0.5.3", - "@eslint/core": "^1.1.1", - "@eslint/plugin-kit": "^0.6.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" + "node": ">=6.9.0" }, "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/eslint-scope": { - "version": "9.1.2", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "license": "MIT", "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/espree": { - "version": "11.2.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "license": "MIT", "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/esquery": { - "version": "1.7.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=0.10" - } - }, - "cli/node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "dev": true, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", "license": "MIT", "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "cli/node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "dev": true, - "license": "MIT", + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">= 16" + "node": ">=6.9.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "cli/node_modules/ethers": { - "version": "6.16.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", "license": "MIT", - "peer": true, "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/ethers/node_modules/@noble/curves": { - "version": "1.2.0", - "dev": true, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", "license": "MIT", "dependencies": { - "@noble/hashes": "1.3.2" + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "cli/node_modules/ethers/node_modules/@noble/hashes": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "cli/node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "dev": true, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" - } - }, - "cli/node_modules/ethers/node_modules/tslib": { - "version": "2.7.0", - "dev": true, - "license": "0BSD" - }, - "cli/node_modules/ethers/node_modules/undici-types": { - "version": "6.19.8", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/eventemitter3": { - "version": "5.0.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/fast-equals": { - "version": "5.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "cli/node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/fast-string-truncated-width": { - "version": "3.0.3", - "license": "MIT" - }, - "cli/node_modules/fast-string-width": { - "version": "3.0.2", + "node_modules/@babel/preset-react": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.29.7.tgz", + "integrity": "sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==", "license": "MIT", "dependencies": { - "fast-string-truncated-width": "^3.0.2" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-transform-react-display-name": "^7.29.7", + "@babel/plugin-transform-react-jsx": "^7.29.7", + "@babel/plugin-transform-react-jsx-development": "^7.29.7", + "@babel/plugin-transform-react-pure-annotations": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/fast-wrap-ansi": { - "version": "0.2.0", + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", "license": "MIT", "dependencies": { - "fast-string-width": "^3.0.2" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "cli/node_modules/file-entry-cache": { - "version": "8.0.0", - "dev": true, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, "engines": { - "node": ">=16.0.0" + "node": ">=6.9.0" } }, - "cli/node_modules/find-replace": { - "version": "3.0.0", - "dev": true, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "array-back": "^3.0.1" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.9.0" } }, - "cli/node_modules/find-up": { - "version": "5.0.0", - "dev": true, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.9.0" } }, - "cli/node_modules/flat-cache": { - "version": "4.0.1", - "dev": true, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { - "node": ">=16" + "node": ">=6.9.0" } }, - "cli/node_modules/flatted": { - "version": "3.3.4", - "dev": true, - "license": "ISC" + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" }, - "cli/node_modules/foreground-child": { - "version": "3.3.1", + "node_modules/@changesets/apply-release-plan": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.1.0.tgz", + "integrity": "sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@changesets/config": "^3.1.3", + "@changesets/get-version-range-type": "^0.4.0", + "@changesets/git": "^3.0.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" } }, - "cli/node_modules/fs-extra": { - "version": "11.3.3", + "node_modules/@changesets/assemble-release-plan": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.9.tgz", + "integrity": "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==", + "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "cli/node_modules/get-caller-file": { - "version": "2.0.5", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" } }, - "cli/node_modules/get-tsconfig": { - "version": "4.13.6", + "node_modules/@changesets/changelog-git": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", + "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", "dev": true, "license": "MIT", "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "@changesets/types": "^6.1.0" } }, - "cli/node_modules/glob": { - "version": "10.5.0", + "node_modules/@changesets/cli": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.30.0.tgz", + "integrity": "sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "@changesets/apply-release-plan": "^7.1.0", + "@changesets/assemble-release-plan": "^6.0.9", + "@changesets/changelog-git": "^0.2.1", + "@changesets/config": "^3.1.3", + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/get-release-plan": "^4.0.15", + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@changesets/write": "^0.4.0", + "@inquirer/external-editor": "^1.0.2", + "@manypkg/get-packages": "^1.1.3", + "ansi-colors": "^4.1.3", + "enquirer": "^2.4.1", + "fs-extra": "^7.0.1", + "mri": "^1.2.0", + "package-manager-detector": "^0.2.0", + "picocolors": "^1.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^3.0.1", + "term-size": "^2.1.0" }, "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "changeset": "bin.js" } }, - "cli/node_modules/glob-parent": { - "version": "6.0.2", + "node_modules/@changesets/config": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.3.tgz", + "integrity": "sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.3", + "@changesets/logger": "^0.1.1", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.8" } }, - "cli/node_modules/glob/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", + "node_modules/@changesets/errors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", + "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "extendable-error": "^0.1.5" } }, - "cli/node_modules/glob/node_modules/minimatch": { - "version": "9.0.9", + "node_modules/@changesets/get-dependents-graph": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz", + "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "picocolors": "^1.1.0", + "semver": "^7.5.3" } }, - "cli/node_modules/hardhat": { - "version": "3.1.10", + "node_modules/@changesets/get-release-plan": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.15.tgz", + "integrity": "sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@nomicfoundation/edr": "0.12.0-next.24", - "@nomicfoundation/hardhat-errors": "^3.0.7", - "@nomicfoundation/hardhat-utils": "^4.0.0", - "@nomicfoundation/hardhat-vendored": "^3.0.1", - "@nomicfoundation/hardhat-zod-utils": "^3.0.2", - "@nomicfoundation/solidity-analyzer": "^0.1.1", - "@sentry/core": "^9.4.0", - "adm-zip": "^0.4.16", - "chalk": "^5.3.0", - "chokidar": "^4.0.3", - "debug": "^4.3.2", - "enquirer": "^2.3.0", - "ethereum-cryptography": "^2.2.1", - "micro-eth-signer": "^0.14.0", - "p-map": "^7.0.2", - "resolve.exports": "^2.0.3", - "semver": "^7.6.3", - "tsx": "^4.19.3", - "ws": "^8.18.0", - "zod": "^3.23.8" - }, - "bin": { - "hardhat": "dist/src/cli.js" + "@changesets/assemble-release-plan": "^6.0.9", + "@changesets/config": "^3.1.3", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" } }, - "cli/node_modules/hardhat/node_modules/ws": { - "version": "8.19.0", + "node_modules/@changesets/get-version-range-type": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", + "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } + "license": "MIT" }, - "cli/node_modules/hash.js": { - "version": "1.1.7", + "node_modules/@changesets/git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", + "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "@changesets/errors": "^0.2.0", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.8", + "spawndamnit": "^3.0.1" } }, - "cli/node_modules/hmac-drbg": { - "version": "1.0.1", + "node_modules/@changesets/logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", + "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", "dev": true, "license": "MIT", "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "picocolors": "^1.1.0" } }, - "cli/node_modules/immer": { - "version": "10.0.2", + "node_modules/@changesets/parse": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.3.tgz", + "integrity": "sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==", "dev": true, "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" + "dependencies": { + "@changesets/types": "^6.1.0", + "js-yaml": "^4.1.1" } }, - "cli/node_modules/inquirer": { - "version": "13.3.0", + "node_modules/@changesets/pre": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", + "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", + "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.3", - "@inquirer/core": "^11.1.5", - "@inquirer/prompts": "^8.3.0", - "@inquirer/type": "^4.0.3", - "mute-stream": "^3.0.0", - "run-async": "^4.0.6", - "rxjs": "^7.8.2" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "@changesets/errors": "^0.2.0", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" } }, - "cli/node_modules/is-plain-obj": { - "version": "2.1.0", + "node_modules/@changesets/read": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.7.tgz", + "integrity": "sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/parse": "^0.4.3", + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0", + "picocolors": "^1.1.0" } }, - "cli/node_modules/is-unicode-supported": { - "version": "0.1.0", + "node_modules/@changesets/should-skip-package": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", + "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" } }, - "cli/node_modules/isows": { - "version": "1.0.7", + "node_modules/@changesets/types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", + "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } + "license": "MIT" }, - "cli/node_modules/jackspeak": { - "version": "3.4.3", + "node_modules/@changesets/write": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", + "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "human-id": "^4.1.1", + "prettier": "^2.7.1" } }, - "cli/node_modules/jest-diff": { - "version": "29.7.0", - "dev": true, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "license": "Apache-2.0" + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, + "optional": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.1.90" } }, - "cli/node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", + "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "cli/node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "dev": true, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "cli/node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "cli/node_modules/jest-get-type": { - "version": "29.6.3", - "dev": true, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" } }, - "cli/node_modules/js-sha3": { - "version": "0.8.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/json-stream-stringify": { - "version": "3.1.6", - "dev": true, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", + "peer": true, "engines": { - "node": ">=7.10.1" + "node": ">=18" } }, - "cli/node_modules/json-stringify-safe": { - "version": "5.0.1", - "dev": true, - "license": "ISC" - }, - "cli/node_modules/jsonfile": { - "version": "6.2.0", + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" + "engines": { + "node": ">=18" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "cli/node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-alpha-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz", + "integrity": "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", + "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/lodash-es": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/lodash.camelcase": { - "version": "4.3.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/log-symbols": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" } }, - "cli/node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", "license": "MIT", + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, - "cli/node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz", + "integrity": "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-color-function-display-p3-linear": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz", + "integrity": "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "has-flag": "^4.0.0" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/lru-cache": { - "version": "10.4.3", - "dev": true, - "license": "ISC" - }, - "cli/node_modules/micro-eth-signer": { - "version": "0.14.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz", + "integrity": "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "micro-packed": "~0.7.2" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/micro-eth-signer/node_modules/@noble/curves": { - "version": "1.8.2", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz", + "integrity": "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "@noble/hashes": "1.7.2" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/micro-eth-signer/node_modules/@noble/hashes": { - "version": "1.7.2", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz", + "integrity": "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/micro-packed": { - "version": "0.7.3", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-contrast-color-function": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz", + "integrity": "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "@scure/base": "~1.2.5" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/micro-packed/node_modules/@scure/base": { - "version": "1.2.6", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "cli/node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/minimatch": { - "version": "10.2.4", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", + "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "cli/node_modules/minipass": { - "version": "7.1.3", - "dev": true, - "license": "BlueOak-1.0.0", "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "cli/node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" + "node": ">=18" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/mocha": { - "version": "11.7.5", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "browser-stdout": "^1.3.1", - "chokidar": "^4.0.1", - "debug": "^4.3.5", - "diff": "^7.0.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^9.0.5", - "ms": "^2.1.3", - "picocolors": "^1.1.1", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^9.2.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "cli/node_modules/mocha/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/mocha/node_modules/minimatch": { - "version": "9.0.9", - "dev": true, - "license": "ISC", + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", + "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "brace-expansion": "^2.0.2" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "cli/node_modules/mute-stream": { - "version": "3.0.0", - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/ndjson": { - "version": "2.0.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz", + "integrity": "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "json-stringify-safe": "^5.0.1", - "minimist": "^1.2.5", - "readable-stream": "^3.6.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "ndjson": "cli.js" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/optionator": { - "version": "0.9.4", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz", + "integrity": "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ox": { - "version": "0.14.0", - "dev": true, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz", + "integrity": "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/wevm" + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" } ], - "license": "MIT", + "license": "MIT-0", "dependencies": { - "@adraffy/ens-normalize": "^1.11.0", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "1.9.1", - "@noble/hashes": "^1.8.0", - "@scure/bip32": "^1.7.0", - "@scure/bip39": "^1.6.0", - "abitype": "^1.2.3", - "eventemitter3": "5.0.1" + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" }, - "peerDependencies": { - "typescript": ">=5.4.0" + "engines": { + "node": ">=18" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ox/node_modules/@adraffy/ens-normalize": { - "version": "1.11.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/ox/node_modules/@noble/ciphers": { - "version": "1.3.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-initial": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", + "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ox/node_modules/@noble/curves": { - "version": "1.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", + "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ox/node_modules/@noble/hashes": { - "version": "1.8.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "cli/node_modules/ox/node_modules/@scure/base": { - "version": "1.2.6", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" } }, - "cli/node_modules/ox/node_modules/@scure/bip32": { - "version": "1.7.0", - "dev": true, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", "license": "MIT", + "peer": true, "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=4" } }, - "cli/node_modules/ox/node_modules/@scure/bip39": { - "version": "1.6.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz", + "integrity": "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/p-map": { - "version": "7.0.4", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/package-json-from-dist": { - "version": "1.0.1", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "cli/node_modules/path-scurry": { - "version": "1.11.1", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", + "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/pretty-format": { - "version": "29.7.0", - "dev": true, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", + "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "cli/node_modules/react-is": { - "version": "18.3.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/readdirp": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" + "node": ">=18" }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "cli/node_modules/reduce-flatten": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "cli/node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "cli/node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "cli/node_modules/resolve.exports": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "cli/node_modules/rfdc": { - "version": "1.4.1", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/run-async": { - "version": "4.0.6", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "cli/node_modules/rxjs": { - "version": "7.8.2", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "cli/node_modules/split2": { - "version": "3.2.2", - "dev": true, - "license": "ISC", - "dependencies": { - "readable-stream": "^3.0.0" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/string-format": { - "version": "2.0.0", - "dev": true, - "license": "WTFPL OR MIT" - }, - "cli/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", + "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "ansi-regex": "^5.0.1" + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" - } - }, - "cli/node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.1.tgz", + "integrity": "sha512-TQUGBuRvxdc7TgNSTevYqrL8oItxiwPDixk20qCB5me/W8uF7BPbhRrAvFuhEoywQp/woRsUZ6SJ+sU5idZAIA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "has-flag": "^4.0.0" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/table-layout": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz", + "integrity": "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">=8.0.0" - } - }, - "cli/node_modules/table-layout/node_modules/array-back": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/table-layout/node_modules/typical": { - "version": "5.2.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-position-area-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-position-area-property/-/postcss-position-area-property-1.0.0.tgz", + "integrity": "sha512-fUP6KR8qV2NuUZV3Cw8itx0Ep90aRjAZxAEzC3vrl6yjFv+pFsQbR18UuQctEKmA72K9O27CoYiKEgXxkqjg8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": ">=8" - } - }, - "cli/node_modules/through2": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "3" - } - }, - "cli/node_modules/ts-command-line-args": { - "version": "2.5.1", - "dev": true, - "license": "ISC", - "dependencies": { - "chalk": "^4.1.0", - "command-line-args": "^5.1.1", - "command-line-usage": "^6.1.0", - "string-format": "^2.0.0" + "node": ">=18" }, - "bin": { - "write-markdown": "dist/write-markdown.js" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ts-command-line-args/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz", + "integrity": "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "color-convert": "^2.0.1" + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ts-command-line-args/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-property-rule-prelude-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-property-rule-prelude-list/-/postcss-property-rule-prelude-list-1.0.0.tgz", + "integrity": "sha512-IxuQjUXq19fobgmSSvUDO7fVwijDJaZMvWQugxfEUxmjBeDCVaDuMpsZ31MsTm5xbnhA+ElDi0+rQ7sQQGisFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/ts-command-line-args/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-random-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", + "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "has-flag": "^4.0.0" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { - "node": ">=8" - } - }, - "cli/node_modules/ts-essentials": { - "version": "7.0.3", - "dev": true, - "license": "MIT", + "node": ">=18" + }, "peerDependencies": { - "typescript": ">=3.7.0" + "postcss": "^8.4" } }, - "cli/node_modules/tsx": { - "version": "4.21.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz", + "integrity": "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18" }, - "optionalDependencies": { - "fsevents": "~2.3.3" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/tunnel": { - "version": "0.0.6", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/type-check": { - "version": "0.4.0", - "dev": true, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, - "cli/node_modules/typechain": { - "version": "8.3.2", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", + "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "@types/prettier": "^2.1.1", - "debug": "^4.3.1", - "fs-extra": "^7.0.0", - "glob": "7.1.7", - "js-sha3": "^0.8.0", - "lodash": "^4.17.15", - "mkdirp": "^1.0.4", - "prettier": "^2.3.1", - "ts-command-line-args": "^2.2.0", - "ts-essentials": "^7.0.1" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, - "bin": { - "typechain": "dist/cli/cli.js" + "engines": { + "node": ">=18" }, "peerDependencies": { - "typescript": ">=4.3.0" - } - }, - "cli/node_modules/typechain/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/typechain/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "postcss": "^8.4" } }, - "cli/node_modules/typechain/node_modules/fs-extra": { - "version": "7.0.1", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", + "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/typechain/node_modules/glob": { - "version": "7.1.7", - "dev": true, - "license": "ISC", + "node_modules/@csstools/postcss-syntax-descriptor-syntax-production": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-syntax-descriptor-syntax-production/-/postcss-syntax-descriptor-syntax-production-1.0.1.tgz", + "integrity": "sha512-GneqQWefjM//f4hJ/Kbox0C6f2T7+pi4/fqTqOFGTL3EjnvOReTqO1qUQ30CaUjkwjYq9qZ41hzarrAxCc4gow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { - "node": "*" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "cli/node_modules/typechain/node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/typechain/node_modules/minimatch": { - "version": "3.1.5", - "dev": true, - "license": "ISC", + "node_modules/@csstools/postcss-system-ui-font-family": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-system-ui-font-family/-/postcss-system-ui-font-family-1.0.0.tgz", + "integrity": "sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "brace-expansion": "^1.1.7" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, "engines": { - "node": "*" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/typechain/node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "cli/node_modules/typescript": { - "version": "5.8.3", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "cli/node_modules/typical": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "cli/node_modules/undici": { - "version": "5.29.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", + "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "dependencies": { - "@fastify/busboy": "^2.0.0" + "@csstools/color-helpers": "^5.1.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=14.0" - } - }, - "cli/node_modules/undici-types": { - "version": "6.21.0", - "devOptional": true, - "license": "MIT" - }, - "cli/node_modules/universalify": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/viem": { - "version": "2.47.0", - "dev": true, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", + "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/wevm" + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" } ], - "license": "MIT", - "peer": true, + "license": "MIT-0", "dependencies": { - "@noble/curves": "1.9.1", - "@noble/hashes": "1.8.0", - "@scure/bip32": "1.7.0", - "@scure/bip39": "1.6.0", - "abitype": "1.2.3", - "isows": "1.0.7", - "ox": "0.14.0", - "ws": "8.18.3" + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" }, - "peerDependencies": { - "typescript": ">=5.0.4" + "engines": { + "node": ">=18" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/viem/node_modules/@noble/curves": { - "version": "1.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/viem/node_modules/@noble/hashes": { - "version": "1.8.0", - "dev": true, - "license": "MIT", + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": "^14.21.3 || >=16" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "postcss": "^8.4" } }, - "cli/node_modules/viem/node_modules/@scure/base": { - "version": "1.2.6", - "dev": true, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=10.0.0" } }, - "cli/node_modules/viem/node_modules/@scure/bip32": { - "version": "1.7.0", - "dev": true, + "node_modules/@docsearch/core": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.3.tgz", + "integrity": "sha512-rUOujwIpxJRgD7+kicVsI3D5sqBvdiRTquzWBpTEXZs8ZXfGbfzpus5HqumaNYTppN2HvH8E2yNuRwYdHJeOlA==", "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } } }, - "cli/node_modules/viem/node_modules/@scure/bip39": { - "version": "1.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } + "node_modules/@docsearch/css": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.3.tgz", + "integrity": "sha512-nlOwcXcsNAptQl4vlL4MA78qNJKO0Qlds5GuBjCoePgkebTXLSf8Qt1oyZ3YBshYupKXG9VRGEsk1zr23d+bzQ==", + "license": "MIT" }, - "cli/node_modules/viem/node_modules/ws": { - "version": "8.18.3", - "dev": true, + "node_modules/@docsearch/react": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.3.tgz", + "integrity": "sha512-Bg2wdDsoQVlNCcEKuEJAU04tvHCqgx8rIu+uIoM4pRtcx3TBKJuXutJik3LTA8LRc9YEyHkrYUrmcC0D7BYf+g==", "license": "MIT", - "engines": { - "node": ">=10.0.0" + "dependencies": { + "@algolia/autocomplete-core": "1.19.2", + "@docsearch/core": "4.6.3", + "@docsearch/css": "4.6.3" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" }, "peerDependenciesMeta": { - "bufferutil": { + "@types/react": { "optional": true }, - "utf-8-validate": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { "optional": true } } }, - "cli/node_modules/word-wrap": { - "version": "1.2.5", - "dev": true, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" } }, - "cli/node_modules/wordwrapjs": { - "version": "4.0.1", - "dev": true, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", "license": "MIT", "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.2.0" + "@algolia/autocomplete-shared": "1.19.2" }, - "engines": { - "node": ">=8.0.0" + "peerDependencies": { + "search-insights": ">= 1 < 3" } }, - "cli/node_modules/wordwrapjs/node_modules/typical": { - "version": "5.2.0", - "dev": true, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-shared": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", "license": "MIT", - "engines": { - "node": ">=8" + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, - "cli/node_modules/workerpool": { - "version": "9.3.4", - "dev": true, - "license": "Apache-2.0" - }, - "cli/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "dev": true, + "node_modules/@docusaurus/babel": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.10.1.tgz", + "integrity": "sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=20.0" } }, - "cli/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/@docusaurus/babel/node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=14.14" } }, - "cli/node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "dev": true, + "node_modules/@docusaurus/babel/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "cli/node_modules/ws": { - "version": "8.17.1", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "universalify": "^2.0.0" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "cli/node_modules/y18n": { - "version": "5.0.8", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "cli/node_modules/yargs": { - "version": "17.7.2", - "dev": true, + "node_modules/@docusaurus/babel/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "cli/node_modules/yargs-parser": { - "version": "21.1.1", - "dev": true, - "license": "ISC", "engines": { - "node": ">=12" + "node": ">= 10.0.0" } }, - "cli/node_modules/yargs-unparser": { - "version": "2.0.0", - "dev": true, + "node_modules/@docusaurus/bundler": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.10.1.tgz", + "integrity": "sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw==", "license": "MIT", "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.10.1", + "@docusaurus/cssnano-preset": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.3", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.11.0", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.2", + "null-loader": "^4.0.1", + "postcss": "^8.5.4", + "postcss-loader": "^7.3.4", + "postcss-preset-env": "^10.2.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^7.0.0" }, "engines": { - "node": ">=10" - } - }, - "cli/node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "cli/node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "node": ">=20.0" }, - "engines": { - "node": ">=8" - } - }, - "cli/node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "peerDependencies": { + "@docusaurus/faster": "*" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } } }, - "cli/node_modules/zod": { - "version": "3.25.76", - "dev": true, + "node_modules/@docusaurus/core": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.10.1.tgz", + "integrity": "sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w==", "license": "MIT", "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@algolia/abtesting": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.21.1.tgz", - "integrity": "sha512-Wia5/mNTfiU0PIUN25UMfAGGdASkkwuCS9nBAdmhqrNPY/ff7U/6MgBVdwFDPsa3sA1msutPtO50gvOzx6MOXA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/autocomplete-core": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.9.tgz", - "integrity": "sha512-4U2JKLMWlDu0CotYyUkWakDxr8AIav3QtIUXXRpfavYN29aVWfzlwJp9T0rPKEf/dO2QCPAUc0Kq1Tj1GJxo2A==", - "license": "MIT", - "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.19.9", - "@algolia/autocomplete-shared": "1.19.9" - } - }, - "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.9.tgz", - "integrity": "sha512-6mExC6X7762s2SV3eJy3QOkB8bdMmnUhQ2agvGVDuzwoGyr3PquGSY/0vPQXCfiAiCaXUz1rXn+lwghgSi0l0w==", - "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.19.9" + "@docusaurus/babel": "3.10.1", + "@docusaurus/bundler": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "execa": "^5.1.1", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.6.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "open": "^8.4.0", + "p-map": "^4.0.0", + "prompts": "^2.4.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.3", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.7", + "tinypool": "^1.0.2", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "webpack": "^5.95.0", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-dev-server": "^5.2.2", + "webpack-merge": "^6.0.1" }, - "peerDependencies": { - "search-insights": ">= 1 < 3" - } - }, - "node_modules/@algolia/autocomplete-shared": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.9.tgz", - "integrity": "sha512-YosP9Uoek6y/Ur1r1qeogk4biMe/hzkyNcgMCciw0//3XpCM7VlYLSHnyt/vOnEOGhCCc0+3v+unEiH6zz+Z1A==", - "license": "MIT", - "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" - } - }, - "node_modules/@algolia/client-abtesting": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.55.1.tgz", - "integrity": "sha512-miW8RzAtBgNiEJ9fGEhsOPgWUpekAe64YcVufqXrlykj0Jjmo5nj0a5f/HAzRVX5ZuU1GAVd7BkzFDx7q50P3A==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/client-analytics": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.55.1.tgz", - "integrity": "sha512-eR3J3kB9JX6DdCvDRi3I4KPfwO6fR9HWYRXhVke2TXIoOQafMKCRAneg33JRmIrb+DnnJ/eWApJLF1O1CLPERg==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/client-common": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", - "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", - "license": "MIT", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/client-insights": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.55.1.tgz", - "integrity": "sha512-OVtj9uA//+pjvKQI5INnzbyLrf3ClNv3XRbWswwJ2kHIStQNHtBfHo+LofNB/WhM9xjuXlW5ANn2aMj65UGx7w==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/client-personalization": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.55.1.tgz", - "integrity": "sha512-oKlVFlp+qbIEe4p7E54zSiP2gEV/vDu972Ykv8VDMFwEvreS7m0YKA3a8hGGHwc7yiBUGGiR3LlwzMLfnJmy6Q==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/client-query-suggestions": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.55.1.tgz", - "integrity": "sha512-BOVrld6vdtsFmotVDMTVQfYXwrVplJ+DUvy60JFi+tkWV698q2J9NNPKEO3dr5qxtSLKQP4vHF8n+3U5PDWhOQ==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/client-search": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.55.1.tgz", - "integrity": "sha512-GAqHl9zERhC3bbBfubwUu07G3UXO06gORvOcsiTBZB3et0s3auNUbHlYdYNp4VKa3sUZqH5AcD3OKzU/KDGXjQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/events": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", - "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", - "license": "MIT" - }, - "node_modules/@algolia/ingestion": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.55.1.tgz", - "integrity": "sha512-BXZw+C+gsWL7pZvbnhJUnCXASiDLGcQxVV7h55Pyh2DmSzwdZIVccE5xc9RVD2trtrhIqk5smuODTxtaZqd0IA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/monitoring": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.55.1.tgz", - "integrity": "sha512-9g/ceZrZTqA62FA3588Xj0onRPjDNfu0pVQqefK0rrHp9H6Wblph/YmzGjZ2g8uqbTh0ZGIvAGCzErU8f7MHpA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/recommend": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.55.1.tgz", - "integrity": "sha512-cZTIrGyAP+W4A6jDVwvWM/JOaoJKQkD/2a5eLUEeNdKAD45jN7BCpsMDONyhZlosLa4UwL8uiINQzj4iFy9nqg==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1", - "@algolia/requester-browser-xhr": "5.55.1", - "@algolia/requester-fetch": "5.55.1", - "@algolia/requester-node-http": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/requester-browser-xhr": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.55.1.tgz", - "integrity": "sha512-N6I3leW0UO8Y9Zv90yo2UHgYGuxZO0mjbvzNxDIJDjO0qECEF7Z9XMvSNeUWXQh/iNDA9lr8MfEy3rmZGIcclw==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/requester-fetch": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.55.1.tgz", - "integrity": "sha512-ukU5zeeFs44rQkzv+TRdYard+d+3lmPGs8lPZhHtWE8rfz+LlBSF6s9kP3VQ7LeOYL8Dz0u6tZfnyTrqrumbHQ==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@algolia/requester-node-http": { - "version": "5.55.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.55.1.tgz", - "integrity": "sha512-lCwXyijwPm3vbYHpBXPRomMcD6mgiptmps27gnMCf4HK+u/AOeFPBnIFh4V3l4A5SnP9VRiKBZqwGBpUH0vaTg==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.55.1" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@antfu/install-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", - "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", - "license": "MIT", - "dependencies": { - "package-manager-detector": "^1.3.0", - "tinyexec": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@antfu/install-pkg/node_modules/package-manager-detector": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.7.0.tgz", - "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==", - "license": "MIT" - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=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==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", - "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.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==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", - "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/traverse": "^7.29.7", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", - "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", - "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "debug": "^4.4.3", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.11" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", - "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", - "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", - "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-wrap-function": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", - "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", - "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", - "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", - "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", - "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", - "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", - "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", - "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/plugin-transform-optional-chaining": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", - "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", - "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", - "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", - "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", - "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", - "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", - "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", - "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", - "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", - "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", - "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", - "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", - "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", - "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/template": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", - "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", - "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", - "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", - "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", - "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", - "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", - "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", - "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", - "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", - "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", - "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", - "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", - "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", - "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", - "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", - "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", - "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", - "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", - "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", - "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", - "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", - "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", - "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", - "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", - "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", - "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", - "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", - "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", - "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", - "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.29.7.tgz", - "integrity": "sha512-J0wGhKan+rIiE2OhfhRptySLrJ6SjQYM6b6N1FMlhyhCcw1Mig8vQjWchyB+bgHGDvaWo6Diu6CLRMra2uMtmg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz", - "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz", - "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-jsx": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz", - "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==", - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz", - "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", - "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", - "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", - "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz", - "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", - "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", - "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", - "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", - "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", - "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", - "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/plugin-syntax-typescript": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", - "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", - "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", - "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", - "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", - "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", - "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.29.7", - "@babel/plugin-syntax-import-attributes": "^7.29.7", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.29.7", - "@babel/plugin-transform-async-generator-functions": "^7.29.7", - "@babel/plugin-transform-async-to-generator": "^7.29.7", - "@babel/plugin-transform-block-scoped-functions": "^7.29.7", - "@babel/plugin-transform-block-scoping": "^7.29.7", - "@babel/plugin-transform-class-properties": "^7.29.7", - "@babel/plugin-transform-class-static-block": "^7.29.7", - "@babel/plugin-transform-classes": "^7.29.7", - "@babel/plugin-transform-computed-properties": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-dotall-regex": "^7.29.7", - "@babel/plugin-transform-duplicate-keys": "^7.29.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", - "@babel/plugin-transform-dynamic-import": "^7.29.7", - "@babel/plugin-transform-explicit-resource-management": "^7.29.7", - "@babel/plugin-transform-exponentiation-operator": "^7.29.7", - "@babel/plugin-transform-export-namespace-from": "^7.29.7", - "@babel/plugin-transform-for-of": "^7.29.7", - "@babel/plugin-transform-function-name": "^7.29.7", - "@babel/plugin-transform-json-strings": "^7.29.7", - "@babel/plugin-transform-literals": "^7.29.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", - "@babel/plugin-transform-member-expression-literals": "^7.29.7", - "@babel/plugin-transform-modules-amd": "^7.29.7", - "@babel/plugin-transform-modules-commonjs": "^7.29.7", - "@babel/plugin-transform-modules-systemjs": "^7.29.7", - "@babel/plugin-transform-modules-umd": "^7.29.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", - "@babel/plugin-transform-new-target": "^7.29.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", - "@babel/plugin-transform-numeric-separator": "^7.29.7", - "@babel/plugin-transform-object-rest-spread": "^7.29.7", - "@babel/plugin-transform-object-super": "^7.29.7", - "@babel/plugin-transform-optional-catch-binding": "^7.29.7", - "@babel/plugin-transform-optional-chaining": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/plugin-transform-private-methods": "^7.29.7", - "@babel/plugin-transform-private-property-in-object": "^7.29.7", - "@babel/plugin-transform-property-literals": "^7.29.7", - "@babel/plugin-transform-regenerator": "^7.29.7", - "@babel/plugin-transform-regexp-modifiers": "^7.29.7", - "@babel/plugin-transform-reserved-words": "^7.29.7", - "@babel/plugin-transform-shorthand-properties": "^7.29.7", - "@babel/plugin-transform-spread": "^7.29.7", - "@babel/plugin-transform-sticky-regex": "^7.29.7", - "@babel/plugin-transform-template-literals": "^7.29.7", - "@babel/plugin-transform-typeof-symbol": "^7.29.7", - "@babel/plugin-transform-unicode-escapes": "^7.29.7", - "@babel/plugin-transform-unicode-property-regex": "^7.29.7", - "@babel/plugin-transform-unicode-regex": "^7.29.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.15", - "babel-plugin-polyfill-corejs3": "^0.14.0", - "babel-plugin-polyfill-regenerator": "^0.6.6", - "core-js-compat": "^3.48.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", - "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8", - "core-js-compat": "^3.48.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.29.7.tgz", - "integrity": "sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-transform-react-display-name": "^7.29.7", - "@babel/plugin-transform-react-jsx": "^7.29.7", - "@babel/plugin-transform-react-jsx-development": "^7.29.7", - "@babel/plugin-transform-react-pure-annotations": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", - "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-syntax-jsx": "^7.29.7", - "@babel/plugin-transform-modules-commonjs": "^7.29.7", - "@babel/plugin-transform-typescript": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@braintree/sanitize-url": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", - "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", - "license": "MIT" - }, - "node_modules/@changesets/apply-release-plan": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.1.0.tgz", - "integrity": "sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/config": "^3.1.3", - "@changesets/get-version-range-type": "^0.4.0", - "@changesets/git": "^3.0.4", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "detect-indent": "^6.0.0", - "fs-extra": "^7.0.1", - "lodash.startcase": "^4.4.0", - "outdent": "^0.5.0", - "prettier": "^2.7.1", - "resolve-from": "^5.0.0", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/assemble-release-plan": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.9.tgz", - "integrity": "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.3", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/changelog-git": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", - "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0" - } - }, - "node_modules/@changesets/cli": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.30.0.tgz", - "integrity": "sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/apply-release-plan": "^7.1.0", - "@changesets/assemble-release-plan": "^6.0.9", - "@changesets/changelog-git": "^0.2.1", - "@changesets/config": "^3.1.3", - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.3", - "@changesets/get-release-plan": "^4.0.15", - "@changesets/git": "^3.0.4", - "@changesets/logger": "^0.1.1", - "@changesets/pre": "^2.0.2", - "@changesets/read": "^0.6.7", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@changesets/write": "^0.4.0", - "@inquirer/external-editor": "^1.0.2", - "@manypkg/get-packages": "^1.1.3", - "ansi-colors": "^4.1.3", - "enquirer": "^2.4.1", - "fs-extra": "^7.0.1", - "mri": "^1.2.0", - "package-manager-detector": "^0.2.0", - "picocolors": "^1.1.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.3", - "spawndamnit": "^3.0.1", - "term-size": "^2.1.0" - }, - "bin": { - "changeset": "bin.js" - } - }, - "node_modules/@changesets/config": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.3.tgz", - "integrity": "sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.3", - "@changesets/logger": "^0.1.1", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "fs-extra": "^7.0.1", - "micromatch": "^4.0.8" - } - }, - "node_modules/@changesets/errors": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", - "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", - "dev": true, - "license": "MIT", - "dependencies": { - "extendable-error": "^0.1.5" - } - }, - "node_modules/@changesets/get-dependents-graph": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.3.tgz", - "integrity": "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "picocolors": "^1.1.0", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/get-release-plan": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.15.tgz", - "integrity": "sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/assemble-release-plan": "^6.0.9", - "@changesets/config": "^3.1.3", - "@changesets/pre": "^2.0.2", - "@changesets/read": "^0.6.7", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3" - } - }, - "node_modules/@changesets/get-version-range-type": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", - "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@changesets/git": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", - "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@manypkg/get-packages": "^1.1.3", - "is-subdir": "^1.1.1", - "micromatch": "^4.0.8", - "spawndamnit": "^3.0.1" - } - }, - "node_modules/@changesets/logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", - "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.0" - } - }, - "node_modules/@changesets/parse": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.3.tgz", - "integrity": "sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "js-yaml": "^4.1.1" - } - }, - "node_modules/@changesets/pre": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", - "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "fs-extra": "^7.0.1" - } - }, - "node_modules/@changesets/read": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.7.tgz", - "integrity": "sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/git": "^3.0.4", - "@changesets/logger": "^0.1.1", - "@changesets/parse": "^0.4.3", - "@changesets/types": "^6.1.0", - "fs-extra": "^7.0.1", - "p-filter": "^2.1.0", - "picocolors": "^1.1.0" - } - }, - "node_modules/@changesets/should-skip-package": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", - "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3" - } - }, - "node_modules/@changesets/types": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", - "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@changesets/write": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", - "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "fs-extra": "^7.0.1", - "human-id": "^4.1.1", - "prettier": "^2.7.1" - } - }, - "node_modules/@chevrotain/types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", - "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", - "license": "Apache-2.0" - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@csstools/cascade-layer-name-parser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", - "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/media-query-list-parser": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", - "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/postcss-alpha-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz", - "integrity": "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-cascade-layers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", - "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" - } - }, - "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", - "license": "MIT", - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@csstools/postcss-color-function": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz", - "integrity": "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-color-function-display-p3-linear": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz", - "integrity": "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-color-mix-function": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz", - "integrity": "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz", - "integrity": "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-content-alt-text": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz", - "integrity": "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-contrast-color-function": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz", - "integrity": "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-exponential-functions": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", - "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-font-format-keywords": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", - "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-gamut-mapping": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", - "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-gradients-interpolation-method": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz", - "integrity": "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-hwb-function": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz", - "integrity": "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-ic-unit": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz", - "integrity": "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-initial": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", - "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", - "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/selector-specificity": "^5.0.0", - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" - } - }, - "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", - "license": "MIT", - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@csstools/postcss-light-dark-function": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz", - "integrity": "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-logical-float-and-clear": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", - "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-logical-overflow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", - "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-logical-overscroll-behavior": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", - "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-logical-resize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", - "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-logical-viewport-units": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", - "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-media-minmax": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", - "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", - "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-nested-calc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", - "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/utilities": "^2.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-normalize-display-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.1.tgz", - "integrity": "sha512-TQUGBuRvxdc7TgNSTevYqrL8oItxiwPDixk20qCB5me/W8uF7BPbhRrAvFuhEoywQp/woRsUZ6SJ+sU5idZAIA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-oklab-function": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz", - "integrity": "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-position-area-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-position-area-property/-/postcss-position-area-property-1.0.0.tgz", - "integrity": "sha512-fUP6KR8qV2NuUZV3Cw8itx0Ep90aRjAZxAEzC3vrl6yjFv+pFsQbR18UuQctEKmA72K9O27CoYiKEgXxkqjg8Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz", - "integrity": "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-property-rule-prelude-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-property-rule-prelude-list/-/postcss-property-rule-prelude-list-1.0.0.tgz", - "integrity": "sha512-IxuQjUXq19fobgmSSvUDO7fVwijDJaZMvWQugxfEUxmjBeDCVaDuMpsZ31MsTm5xbnhA+ElDi0+rQ7sQQGisFA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-random-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", - "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-relative-color-syntax": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz", - "integrity": "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/postcss-progressive-custom-properties": "^4.2.1", - "@csstools/utilities": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-scope-pseudo-class": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", - "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", - "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@csstools/postcss-sign-functions": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", - "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", - "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-syntax-descriptor-syntax-production": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-syntax-descriptor-syntax-production/-/postcss-syntax-descriptor-syntax-production-1.0.1.tgz", - "integrity": "sha512-GneqQWefjM//f4hJ/Kbox0C6f2T7+pi4/fqTqOFGTL3EjnvOReTqO1qUQ30CaUjkwjYq9qZ41hzarrAxCc4gow==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "dependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "bin": { + "docusaurus": "bin/docusaurus.mjs" }, "engines": { - "node": ">=18" + "node": ">=20.0" }, "peerDependencies": { - "postcss": "^8.4" + "@docusaurus/faster": "*", + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } } }, - "node_modules/@csstools/postcss-system-ui-font-family": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-system-ui-font-family/-/postcss-system-ui-font-family-1.0.0.tgz", - "integrity": "sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@docusaurus/core/node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">=14.14" } }, - "node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", - "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@docusaurus/core/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18" + "universalify": "^2.0.0" }, - "peerDependencies": { - "postcss": "^8.4" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", - "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@docusaurus/core/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "aggregate-error": "^3.0.0" }, "engines": { - "node": ">=18" + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@csstools/postcss-unset-value": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", - "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@docusaurus/core/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": ">= 10.0.0" } }, - "node_modules/@csstools/utilities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", - "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.1.tgz", + "integrity": "sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ==", + "license": "MIT", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.5.4", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" }, - "peerDependencies": { - "postcss": "^8.4" + "engines": { + "node": ">=20.0" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "node_modules/@docusaurus/faster": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.10.1.tgz", + "integrity": "sha512-XTZhE5C1gZ/DaYYMlSk02dwP5vhpQON5QHVz1s3892mSESAywgWanURpXEDAvt4GvGuq7s+XP8rTWHZvfaJmdQ==", "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.1", + "@rspack/core": "^1.7.10", + "@swc/core": "^1.7.39", + "@swc/html": "^1.13.5", + "browserslist": "^4.24.2", + "lightningcss": "^1.27.0", + "semver": "^7.5.4", + "swc-loader": "^0.2.6", + "tslib": "^2.6.0", + "webpack": "^5.95.0" + }, "engines": { - "node": ">=10.0.0" + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" } }, - "node_modules/@docsearch/core": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.3.tgz", - "integrity": "sha512-rUOujwIpxJRgD7+kicVsI3D5sqBvdiRTquzWBpTEXZs8ZXfGbfzpus5HqumaNYTppN2HvH8E2yNuRwYdHJeOlA==", + "node_modules/@docusaurus/logger": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.10.1.tgz", + "integrity": "sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw==", "license": "MIT", - "peerDependencies": { - "@types/react": ">= 16.8.0 < 20.0.0", - "react": ">= 16.8.0 < 20.0.0", - "react-dom": ">= 16.8.0 < 20.0.0" + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } + "engines": { + "node": ">=20.0" } }, - "node_modules/@docsearch/css": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.3.tgz", - "integrity": "sha512-nlOwcXcsNAptQl4vlL4MA78qNJKO0Qlds5GuBjCoePgkebTXLSf8Qt1oyZ3YBshYupKXG9VRGEsk1zr23d+bzQ==", - "license": "MIT" - }, - "node_modules/@docsearch/react": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.3.tgz", - "integrity": "sha512-Bg2wdDsoQVlNCcEKuEJAU04tvHCqgx8rIu+uIoM4pRtcx3TBKJuXutJik3LTA8LRc9YEyHkrYUrmcC0D7BYf+g==", + "node_modules/@docusaurus/mdx-loader": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.10.1.tgz", + "integrity": "sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-core": "1.19.2", - "@docsearch/core": "4.6.3", - "@docsearch/css": "4.6.3" + "@docusaurus/logger": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^2.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" }, - "peerDependencies": { - "@types/react": ">= 16.8.0 < 20.0.0", - "react": ">= 16.8.0 < 20.0.0", - "react-dom": ">= 16.8.0 < 20.0.0", - "search-insights": ">= 1 < 3" + "engines": { + "node": ">=20.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "search-insights": { - "optional": true - } + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-core": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", - "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "node_modules/@docusaurus/mdx-loader/node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", - "@algolia/autocomplete-shared": "1.19.2" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" } }, - "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", - "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", + "node_modules/@docusaurus/mdx-loader/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.19.2" + "universalify": "^2.0.0" }, - "peerDependencies": { - "search-insights": ">= 1 < 3" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-shared": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", - "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "node_modules/@docusaurus/mdx-loader/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.1.tgz", + "integrity": "sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w==", "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, "peerDependencies": { - "@algolia/client-search": ">= 4.9.1 < 6", - "algoliasearch": ">= 4.9.1 < 6" + "react": "*", + "react-dom": "*" } }, - "node_modules/@docusaurus/babel": { + "node_modules/@docusaurus/plugin-content-blog": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.10.1.tgz", - "integrity": "sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.1.tgz", + "integrity": "sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA==", "license": "MIT", "dependencies": { - "@babel/core": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.25.9", - "@babel/preset-env": "^7.25.9", - "@babel/preset-react": "^7.25.9", - "@babel/preset-typescript": "^7.25.9", - "@babel/runtime": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", - "babel-plugin-dynamic-import-node": "^2.3.3", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "cheerio": "1.0.0-rc.12", + "combine-promises": "^1.1.0", + "feed": "^4.2.2", "fs-extra": "^11.1.1", - "tslib": "^2.6.0" + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" }, "engines": { "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/babel/node_modules/fs-extra": { + "node_modules/@docusaurus/plugin-content-blog/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -7678,7 +4326,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/babel/node_modules/jsonfile": { + "node_modules/@docusaurus/plugin-content-blog/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -7690,7 +4338,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/babel/node_modules/universalify": { + "node_modules/@docusaurus/plugin-content-blog/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -7699,118 +4347,99 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/bundler": { + "node_modules/@docusaurus/plugin-content-docs": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.10.1.tgz", - "integrity": "sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.1.tgz", + "integrity": "sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ==", "license": "MIT", + "peer": true, "dependencies": { - "@babel/core": "^7.25.9", - "@docusaurus/babel": "3.10.1", - "@docusaurus/cssnano-preset": "3.10.1", + "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/theme-common": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", - "babel-loader": "^9.2.1", - "clean-css": "^5.3.3", - "copy-webpack-plugin": "^11.0.0", - "css-loader": "^6.11.0", - "css-minimizer-webpack-plugin": "^5.0.1", - "cssnano": "^6.1.2", - "file-loader": "^6.2.0", - "html-minifier-terser": "^7.2.0", - "mini-css-extract-plugin": "^2.9.2", - "null-loader": "^4.0.1", - "postcss": "^8.5.4", - "postcss-loader": "^7.3.4", - "postcss-preset-env": "^10.2.1", - "terser-webpack-plugin": "^5.3.9", + "@docusaurus/utils-common": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", "tslib": "^2.6.0", - "url-loader": "^4.1.1", - "webpack": "^5.95.0", - "webpackbar": "^7.0.0" + "utility-types": "^3.10.0", + "webpack": "^5.88.1" }, "engines": { "node": ">=20.0" }, "peerDependencies": { - "@docusaurus/faster": "*" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs/node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, - "peerDependenciesMeta": { - "@docusaurus/faster": { - "optional": true - } + "engines": { + "node": ">=14.14" } }, - "node_modules/@docusaurus/core": { + "node_modules/@docusaurus/plugin-content-docs/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@docusaurus/plugin-content-docs/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.10.1.tgz", - "integrity": "sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.1.tgz", + "integrity": "sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw==", "license": "MIT", - "peer": true, "dependencies": { - "@docusaurus/babel": "3.10.1", - "@docusaurus/bundler": "3.10.1", - "@docusaurus/logger": "3.10.1", + "@docusaurus/core": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-common": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "boxen": "^6.2.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cli-table3": "^0.6.3", - "combine-promises": "^1.1.0", - "commander": "^5.1.0", - "core-js": "^3.31.1", - "detect-port": "^1.5.1", - "escape-html": "^1.0.3", - "eta": "^2.2.0", - "eval": "^0.1.8", - "execa": "^5.1.1", - "fs-extra": "^11.1.1", - "html-tags": "^3.3.1", - "html-webpack-plugin": "^5.6.0", - "leven": "^3.1.0", - "lodash": "^4.17.21", - "open": "^8.4.0", - "p-map": "^4.0.0", - "prompts": "^2.4.2", - "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", - "react-loadable-ssr-addon-v5-slorber": "^1.0.3", - "react-router": "^5.3.4", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.3.4", - "semver": "^7.5.4", - "serve-handler": "^6.1.7", - "tinypool": "^1.0.2", - "tslib": "^2.6.0", - "update-notifier": "^6.0.2", - "webpack": "^5.95.0", - "webpack-bundle-analyzer": "^4.10.2", - "webpack-dev-server": "^5.2.2", - "webpack-merge": "^6.0.1" - }, - "bin": { - "docusaurus": "bin/docusaurus.mjs" + "@docusaurus/utils-validation": "3.10.1", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" }, "engines": { "node": ">=20.0" }, "peerDependencies": { - "@docusaurus/faster": "*", - "@mdx-js/react": "^3.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@docusaurus/faster": { - "optional": true - } } }, - "node_modules/@docusaurus/core/node_modules/fs-extra": { + "node_modules/@docusaurus/plugin-content-pages/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -7824,7 +4453,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/core/node_modules/jsonfile": { + "node_modules/@docusaurus/plugin-content-pages/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -7836,22 +4465,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/core/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@docusaurus/core/node_modules/universalify": { + "node_modules/@docusaurus/plugin-content-pages/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -7860,88 +4474,34 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/cssnano-preset": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.1.tgz", - "integrity": "sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ==", - "license": "MIT", - "dependencies": { - "cssnano-preset-advanced": "^6.1.2", - "postcss": "^8.5.4", - "postcss-sort-media-queries": "^5.2.0", - "tslib": "^2.6.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@docusaurus/faster": { + "node_modules/@docusaurus/plugin-css-cascade-layers": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.10.1.tgz", - "integrity": "sha512-XTZhE5C1gZ/DaYYMlSk02dwP5vhpQON5QHVz1s3892mSESAywgWanURpXEDAvt4GvGuq7s+XP8rTWHZvfaJmdQ==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.1.tgz", + "integrity": "sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw==", "license": "MIT", "dependencies": { + "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", - "@rspack/core": "^1.7.10", - "@swc/core": "^1.7.39", - "@swc/html": "^1.13.5", - "browserslist": "^4.24.2", - "lightningcss": "^1.27.0", - "semver": "^7.5.4", - "swc-loader": "^0.2.6", - "tslib": "^2.6.0", - "webpack": "^5.95.0" - }, - "engines": { - "node": ">=20.0" - }, - "peerDependencies": { - "@docusaurus/types": "*" - } - }, - "node_modules/@docusaurus/logger": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.10.1.tgz", - "integrity": "sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "engines": { "node": ">=20.0" } }, - "node_modules/@docusaurus/mdx-loader": { + "node_modules/@docusaurus/plugin-debug": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.10.1.tgz", - "integrity": "sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.10.1.tgz", + "integrity": "sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.10.1", + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "@mdx-js/mdx": "^3.0.0", - "@slorber/remark-comment": "^1.0.0", - "escape-html": "^1.0.3", - "estree-util-value-to-estree": "^3.0.1", - "file-loader": "^6.2.0", "fs-extra": "^11.1.1", - "image-size": "^2.0.2", - "mdast-util-mdx": "^3.0.0", - "mdast-util-to-string": "^4.0.0", - "rehype-raw": "^7.0.0", - "remark-directive": "^3.0.0", - "remark-emoji": "^4.0.0", - "remark-frontmatter": "^5.0.0", - "remark-gfm": "^4.0.0", - "stringify-object": "^3.3.0", - "tslib": "^2.6.0", - "unified": "^11.0.3", - "unist-util-visit": "^5.0.0", - "url-loader": "^4.1.1", - "vfile": "^6.0.1", - "webpack": "^5.88.1" + "react-json-view-lite": "^2.3.0", + "tslib": "^2.6.0" }, "engines": { "node": ">=20.0" @@ -7951,7 +4511,7 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/mdx-loader/node_modules/fs-extra": { + "node_modules/@docusaurus/plugin-debug/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -7965,7 +4525,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/mdx-loader/node_modules/jsonfile": { + "node_modules/@docusaurus/plugin-debug/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -7977,7 +4537,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/mdx-loader/node_modules/universalify": { + "node_modules/@docusaurus/plugin-debug/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -7986,61 +4546,89 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/module-type-aliases": { + "node_modules/@docusaurus/plugin-google-analytics": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.1.tgz", - "integrity": "sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.1.tgz", + "integrity": "sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA==", "license": "MIT", "dependencies": { + "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "@types/react-router-dom": "*", - "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + "@docusaurus/utils-validation": "3.10.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-content-blog": { + "node_modules/@docusaurus/plugin-google-gtag": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.1.tgz", - "integrity": "sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA==", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.1.tgz", + "integrity": "sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@types/gtag.js": "^0.0.20", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.1.tgz", + "integrity": "sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.1.tgz", + "integrity": "sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg==", "license": "MIT", "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", - "@docusaurus/mdx-loader": "3.10.1", - "@docusaurus/theme-common": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", - "cheerio": "1.0.0-rc.12", - "combine-promises": "^1.1.0", - "feed": "^4.2.2", "fs-extra": "^11.1.1", - "lodash": "^4.17.21", - "schema-dts": "^1.1.2", - "srcset": "^4.0.0", - "tslib": "^2.6.0", - "unist-util-visit": "^5.0.0", - "utility-types": "^3.10.0", - "webpack": "^5.88.1" + "sitemap": "^7.1.1", + "tslib": "^2.6.0" }, "engines": { "node": ">=20.0" }, "peerDependencies": { - "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-content-blog/node_modules/fs-extra": { + "node_modules/@docusaurus/plugin-sitemap/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -8054,7 +4642,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/plugin-content-blog/node_modules/jsonfile": { + "node_modules/@docusaurus/plugin-sitemap/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -8066,7 +4654,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/plugin-content-blog/node_modules/universalify": { + "node_modules/@docusaurus/plugin-sitemap/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -8075,31 +4663,91 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/plugin-content-docs": { + "node_modules/@docusaurus/plugin-svgr": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.1.tgz", + "integrity": "sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "@svgr/core": "8.1.0", + "@svgr/webpack": "^8.1.0", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.10.1.tgz", + "integrity": "sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.1", + "@docusaurus/plugin-content-blog": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/plugin-content-pages": "3.10.1", + "@docusaurus/plugin-css-cascade-layers": "3.10.1", + "@docusaurus/plugin-debug": "3.10.1", + "@docusaurus/plugin-google-analytics": "3.10.1", + "@docusaurus/plugin-google-gtag": "3.10.1", + "@docusaurus/plugin-google-tag-manager": "3.10.1", + "@docusaurus/plugin-sitemap": "3.10.1", + "@docusaurus/plugin-svgr": "3.10.1", + "@docusaurus/theme-classic": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-search-algolia": "3.10.1", + "@docusaurus/types": "3.10.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.1.tgz", - "integrity": "sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ==", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.10.1.tgz", + "integrity": "sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A==", "license": "MIT", - "peer": true, "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/plugin-content-blog": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/plugin-content-pages": "3.10.1", "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-translations": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", - "@types/react-router-config": "^5.0.7", - "combine-promises": "^1.1.0", - "fs-extra": "^11.1.1", - "js-yaml": "^4.1.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.45", "lodash": "^4.17.21", - "schema-dts": "^1.1.2", + "nprogress": "^0.2.0", + "postcss": "^8.5.4", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", "tslib": "^2.6.0", - "utility-types": "^3.10.0", - "webpack": "^5.88.1" + "utility-types": "^3.10.0" }, "engines": { "node": ">=20.0" @@ -8109,55 +4757,85 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-content-docs/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "node_modules/@docusaurus/theme-common": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.10.1.tgz", + "integrity": "sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@docusaurus/mdx-loader": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/utils": "3.10.1", + "@docusaurus/utils-common": "3.10.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" }, "engines": { - "node": ">=14.14" + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-content-docs/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "node_modules/@docusaurus/theme-mermaid": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.10.1.tgz", + "integrity": "sha512-2gxpmln8Pc4EN1oWzshQEx2HTs67jk14v7MmgqGs8ZU7Nm8oihg+fTouof2u4vN8DtB3Fln4cDJu4UprSX1S3Q==", "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "@docusaurus/core": "3.10.1", + "@docusaurus/module-type-aliases": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/types": "3.10.1", + "@docusaurus/utils-validation": "3.10.1", + "mermaid": ">=11.6.0", + "tslib": "^2.6.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@docusaurus/plugin-content-docs/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=20.0" + }, + "peerDependencies": { + "@mermaid-js/layout-elk": "^0.1.9", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@mermaid-js/layout-elk": { + "optional": true + } } }, - "node_modules/@docusaurus/plugin-content-pages": { + "node_modules/@docusaurus/theme-search-algolia": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.1.tgz", - "integrity": "sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw==", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.1.tgz", + "integrity": "sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug==", "license": "MIT", "dependencies": { + "@algolia/autocomplete-core": "^1.19.2", + "@docsearch/react": "^3.9.0 || ^4.3.2", "@docusaurus/core": "3.10.1", - "@docusaurus/mdx-loader": "3.10.1", - "@docusaurus/types": "3.10.1", + "@docusaurus/logger": "3.10.1", + "@docusaurus/plugin-content-docs": "3.10.1", + "@docusaurus/theme-common": "3.10.1", + "@docusaurus/theme-translations": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-validation": "3.10.1", + "algoliasearch": "^5.37.0", + "algoliasearch-helper": "^3.26.0", + "clsx": "^2.0.0", + "eta": "^2.2.0", "fs-extra": "^11.1.1", + "lodash": "^4.17.21", "tslib": "^2.6.0", - "webpack": "^5.88.1" + "utility-types": "^3.10.0" }, "engines": { "node": ">=20.0" @@ -8167,7 +4845,7 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-content-pages/node_modules/fs-extra": { + "node_modules/@docusaurus/theme-search-algolia/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -8181,7 +4859,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/plugin-content-pages/node_modules/jsonfile": { + "node_modules/@docusaurus/theme-search-algolia/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -8193,7 +4871,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/plugin-content-pages/node_modules/universalify": { + "node_modules/@docusaurus/theme-search-algolia/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -8202,44 +4880,20 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/plugin-css-cascade-layers": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.1.tgz", - "integrity": "sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw==", - "license": "MIT", - "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "tslib": "^2.6.0" - }, - "engines": { - "node": ">=20.0" - } - }, - "node_modules/@docusaurus/plugin-debug": { + "node_modules/@docusaurus/theme-translations": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.10.1.tgz", - "integrity": "sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA==", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.10.1.tgz", + "integrity": "sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils": "3.10.1", "fs-extra": "^11.1.1", - "react-json-view-lite": "^2.3.0", "tslib": "^2.6.0" }, "engines": { "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-debug/node_modules/fs-extra": { + "node_modules/@docusaurus/theme-translations/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -8253,7 +4907,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/plugin-debug/node_modules/jsonfile": { + "node_modules/@docusaurus/theme-translations/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -8265,7 +4919,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/plugin-debug/node_modules/universalify": { + "node_modules/@docusaurus/theme-translations/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -8274,89 +4928,107 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/plugin-google-analytics": { + "node_modules/@docusaurus/types": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.1.tgz", - "integrity": "sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA==", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.10.1.tgz", + "integrity": "sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "tslib": "^2.6.0" - }, - "engines": { - "node": ">=20.0" + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-google-gtag": { + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/utils": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.1.tgz", - "integrity": "sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw==", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.10.1.tgz", + "integrity": "sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", + "@docusaurus/logger": "3.10.1", "@docusaurus/types": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "@types/gtag.js": "^0.0.20", - "tslib": "^2.6.0" + "@docusaurus/utils-common": "3.10.1", + "escape-string-regexp": "^4.0.0", + "execa": "^5.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "p-queue": "^6.6.2", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" }, "engines": { "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-google-tag-manager": { + "node_modules/@docusaurus/utils-common": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.1.tgz", - "integrity": "sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw==", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.10.1.tgz", + "integrity": "sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "engines": { "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-sitemap": { + "node_modules/@docusaurus/utils-validation": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.1.tgz", - "integrity": "sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg==", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.10.1.tgz", + "integrity": "sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", - "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "fs-extra": "^11.1.1", - "sitemap": "^7.1.1", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", "tslib": "^2.6.0" }, "engines": { "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/plugin-sitemap/node_modules/fs-extra": { + "node_modules/@docusaurus/utils-validation/node_modules/fs-extra": { "version": "11.3.6", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", @@ -8370,7 +5042,7 @@ "node": ">=14.14" } }, - "node_modules/@docusaurus/plugin-sitemap/node_modules/jsonfile": { + "node_modules/@docusaurus/utils-validation/node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", @@ -8382,7 +5054,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@docusaurus/plugin-sitemap/node_modules/universalify": { + "node_modules/@docusaurus/utils-validation/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -8391,526 +5063,666 @@ "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/plugin-svgr": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.1.tgz", - "integrity": "sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q==", + "node_modules/@docusaurus/utils/node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "@svgr/core": "8.1.0", - "@svgr/webpack": "^8.1.0", - "tslib": "^2.6.0", - "webpack": "^5.88.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": ">=14.14" } }, - "node_modules/@docusaurus/preset-classic": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.10.1.tgz", - "integrity": "sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg==", + "node_modules/@docusaurus/utils/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/plugin-content-blog": "3.10.1", - "@docusaurus/plugin-content-docs": "3.10.1", - "@docusaurus/plugin-content-pages": "3.10.1", - "@docusaurus/plugin-css-cascade-layers": "3.10.1", - "@docusaurus/plugin-debug": "3.10.1", - "@docusaurus/plugin-google-analytics": "3.10.1", - "@docusaurus/plugin-google-gtag": "3.10.1", - "@docusaurus/plugin-google-tag-manager": "3.10.1", - "@docusaurus/plugin-sitemap": "3.10.1", - "@docusaurus/plugin-svgr": "3.10.1", - "@docusaurus/theme-classic": "3.10.1", - "@docusaurus/theme-common": "3.10.1", - "@docusaurus/theme-search-algolia": "3.10.1", - "@docusaurus/types": "3.10.1" + "universalify": "^2.0.0" }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@docusaurus/utils/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", "engines": { - "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": ">= 10.0.0" } }, - "node_modules/@docusaurus/theme-classic": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.10.1.tgz", - "integrity": "sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A==", + "node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", "license": "MIT", + "optional": true, "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/logger": "3.10.1", - "@docusaurus/mdx-loader": "3.10.1", - "@docusaurus/module-type-aliases": "3.10.1", - "@docusaurus/plugin-content-blog": "3.10.1", - "@docusaurus/plugin-content-docs": "3.10.1", - "@docusaurus/plugin-content-pages": "3.10.1", - "@docusaurus/theme-common": "3.10.1", - "@docusaurus/theme-translations": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-common": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "@mdx-js/react": "^3.0.0", - "clsx": "^2.0.0", - "copy-text-to-clipboard": "^3.2.0", - "infima": "0.2.0-alpha.45", - "lodash": "^4.17.21", - "nprogress": "^0.2.0", - "postcss": "^8.5.4", - "prism-react-renderer": "^2.3.0", - "prismjs": "^1.29.0", - "react-router-dom": "^5.3.4", - "rtlcss": "^4.1.0", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=20.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@docusaurus/theme-common": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.10.1.tgz", - "integrity": "sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@docusaurus/mdx-loader": "3.10.1", - "@docusaurus/module-type-aliases": "3.10.1", - "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-common": "3.10.1", - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router-config": "*", - "clsx": "^2.0.0", - "parse-numeric-range": "^1.3.0", - "prism-react-renderer": "^2.3.0", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" }, "engines": { - "node": ">=20.0" - }, - "peerDependencies": { - "@docusaurus/plugin-content-docs": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@docusaurus/theme-mermaid": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.10.1.tgz", - "integrity": "sha512-2gxpmln8Pc4EN1oWzshQEx2HTs67jk14v7MmgqGs8ZU7Nm8oihg+fTouof2u4vN8DtB3Fln4cDJu4UprSX1S3Q==", + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, "license": "MIT", "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/module-type-aliases": "3.10.1", - "@docusaurus/theme-common": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "mermaid": ">=11.6.0", - "tslib": "^2.6.0" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=20.0" + "node": "18 || 20 || >=22" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" }, - "peerDependencies": { - "@mermaid-js/layout-elk": "^0.1.9", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "engines": { + "node": "18 || 20 || >=22" }, - "peerDependenciesMeta": { - "@mermaid-js/layout-elk": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.1.tgz", - "integrity": "sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug==", - "license": "MIT", - "dependencies": { - "@algolia/autocomplete-core": "^1.19.2", - "@docsearch/react": "^3.9.0 || ^4.3.2", - "@docusaurus/core": "3.10.1", - "@docusaurus/logger": "3.10.1", - "@docusaurus/plugin-content-docs": "3.10.1", - "@docusaurus/theme-common": "3.10.1", - "@docusaurus/theme-translations": "3.10.1", - "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-validation": "3.10.1", - "algoliasearch": "^5.37.0", - "algoliasearch-helper": "^3.26.0", - "clsx": "^2.0.0", - "eta": "^2.2.0", - "fs-extra": "^11.1.1", - "lodash": "^4.17.21", - "tslib": "^2.6.0", - "utility-types": "^3.10.0" + "node_modules/@eslint/config-helpers": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" }, "engines": { - "node": ">=20.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", - "license": "MIT", + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=14.14" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "license": "MIT", + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "universalify": "^2.0.0" + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@docusaurus/theme-search-algolia/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" + "node_modules/@fontsource/ibm-plex-sans": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-sans/-/ibm-plex-sans-5.2.8.tgz", + "integrity": "sha512-eztSXjDhPhcpxNIiGTgMebdLP9qS4rWkysuE1V7c+DjOR0qiezaiDaTwQE7bTnG5HxAY/8M43XKDvs3cYq6ZYQ==", + "dev": true, + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" } }, - "node_modules/@docusaurus/theme-translations": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.10.1.tgz", - "integrity": "sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw==", - "license": "MIT", + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", "dependencies": { - "fs-extra": "^11.1.1", - "tslib": "^2.6.0" + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" }, "engines": { - "node": ">=20.0" + "node": ">=18.18.0" } }, - "node_modules/@docusaurus/theme-translations/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", - "license": "MIT", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=14.14" + "node": ">=18.18.0" } }, - "node_modules/@docusaurus/theme-translations/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.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, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", "license": "MIT", "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" } }, - "node_modules/@docusaurus/theme-translations/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/@inquirer/ansi": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, - "node_modules/@docusaurus/types": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.10.1.tgz", - "integrity": "sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw==", + "node_modules/@inquirer/checkbox": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", + "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", "license": "MIT", "dependencies": { - "@mdx-js/mdx": "^3.0.0", - "@types/history": "^4.7.11", - "@types/mdast": "^4.0.2", - "@types/react": "*", - "commander": "^5.1.0", - "joi": "^17.9.2", - "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", - "utility-types": "^3.10.0", - "webpack": "^5.95.0", - "webpack-merge": "^5.9.0" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/types/node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "node_modules/@inquirer/confirm": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", + "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", "license": "MIT", "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=10.0.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/utils": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.10.1.tgz", - "integrity": "sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw==", + "node_modules/@inquirer/core": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.10.1", - "@docusaurus/types": "3.10.1", - "@docusaurus/utils-common": "3.10.1", - "escape-string-regexp": "^4.0.0", - "execa": "^5.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^11.1.1", - "github-slugger": "^1.5.0", - "globby": "^11.1.0", - "gray-matter": "^4.0.3", - "jiti": "^1.20.0", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "micromatch": "^4.0.5", - "p-queue": "^6.6.2", - "prompts": "^2.4.2", - "resolve-pathname": "^3.0.0", - "tslib": "^2.6.0", - "url-loader": "^4.1.1", - "utility-types": "^3.10.0", - "webpack": "^5.88.1" + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=20.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/utils-common": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.10.1.tgz", - "integrity": "sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA==", + "node_modules/@inquirer/editor": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", + "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", "license": "MIT", "dependencies": { - "@docusaurus/types": "3.10.1", - "tslib": "^2.6.0" + "@inquirer/core": "^11.2.1", + "@inquirer/external-editor": "^3.0.3", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=20.0" - } - }, - "node_modules/@docusaurus/utils-validation": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.10.1.tgz", - "integrity": "sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg==", + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor/node_modules/@inquirer/external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.10.1", - "@docusaurus/utils": "3.10.1", - "@docusaurus/utils-common": "3.10.1", - "fs-extra": "^11.2.0", - "joi": "^17.9.2", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "tslib": "^2.6.0" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" }, "engines": { - "node": ">=20.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/utils-validation/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "node_modules/@inquirer/expand": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", + "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=14.14" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/utils-validation/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/utils-validation/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/@inquirer/figures": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, - "node_modules/@docusaurus/utils/node_modules/fs-extra": { - "version": "11.3.6", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", - "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "node_modules/@inquirer/input": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", + "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=14.14" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@docusaurus/utils/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "node_modules/@inquirer/number": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", + "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", "license": "MIT", "dependencies": { - "universalify": "^2.0.0" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@docusaurus/utils/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "node_modules/@inquirer/password": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", + "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "node_modules/@inquirer/prompts": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", + "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@inquirer/checkbox": "^5.2.1", + "@inquirer/confirm": "^6.1.1", + "@inquirer/editor": "^5.2.2", + "@inquirer/expand": "^5.1.1", + "@inquirer/input": "^5.1.2", + "@inquirer/number": "^4.1.1", + "@inquirer/password": "^5.1.1", + "@inquirer/rawlist": "^5.3.1", + "@inquirer/search": "^4.2.1", + "@inquirer/select": "^5.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "node_modules/@inquirer/rawlist": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", + "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@fontsource/ibm-plex-sans": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-sans/-/ibm-plex-sans-5.2.8.tgz", - "integrity": "sha512-eztSXjDhPhcpxNIiGTgMebdLP9qS4rWkysuE1V7c+DjOR0qiezaiDaTwQE7bTnG5HxAY/8M43XKDvs3cYq6ZYQ==", - "dev": true, - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "license": "BSD-3-Clause", + "node_modules/@inquirer/search": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", + "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", + "license": "MIT", "dependencies": { - "@hapi/hoek": "^9.0.0" + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "license": "MIT" - }, - "node_modules/@iconify/utils": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", - "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", + "node_modules/@inquirer/select": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", + "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", "license": "MIT", "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "import-meta-resolve": "^4.2.0" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", - "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", - "dev": true, + "node_modules/@inquirer/type": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" - }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -9609,16 +6421,55 @@ "@module-federation/sdk": "0.22.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", - "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@tybys/wasm-util": "^0.10.1" + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/hashes": { @@ -10056,6 +6907,66 @@ "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==", "license": "MIT" }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@shuding/opentype.js": { "version": "1.4.0-beta.0", "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", @@ -11168,6 +8079,13 @@ "@types/ms": "*" } }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -11323,6 +8241,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -11486,6 +8405,276 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.64.0.tgz", + "integrity": "sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/type-utils": "8.64.0", + "@typescript-eslint/utils": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.64.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.64.0.tgz", + "integrity": "sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.64.0.tgz", + "integrity": "sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.64.0", + "@typescript-eslint/types": "^8.64.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.64.0.tgz", + "integrity": "sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.64.0.tgz", + "integrity": "sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.64.0.tgz", + "integrity": "sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/utils": "8.64.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.64.0.tgz", + "integrity": "sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.64.0.tgz", + "integrity": "sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.64.0", + "@typescript-eslint/tsconfig-utils": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/visitor-keys": "8.64.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.64.0.tgz", + "integrity": "sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.64.0", + "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.64.0.tgz", + "integrity": "sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.64.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.2.tgz", @@ -11667,6 +8856,27 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/abitype": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", + "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -13067,6 +10277,15 @@ "node": ">=8" } }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -14589,6 +11808,13 @@ "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, + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -15049,163 +12275,432 @@ "once": "^1.4.0" } }, - "node_modules/enhanced-resolve": { - "version": "5.24.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.1.tgz", - "integrity": "sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==", + "node_modules/enhanced-resolve": { + "version": "5.24.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.1.tgz", + "integrity": "sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", + "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-toolkit": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", + "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.7.0.tgz", + "integrity": "sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==", + "dev": true, + "license": "MIT", + "peer": true, + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "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/eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, "engines": { - "node": ">=10.13.0" + "node": "18 || 20 || >=22" } }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=8.6" + "node": "18 || 20 || >=22" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=0.12" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" + "node": ">=4.0" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/eslint/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, "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es-module-lexer": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz", - "integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==", - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", "dependencies": { - "es-errors": "^1.3.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">=10.13.0" } }, - "node_modules/es-toolkit": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", - "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] + "node_modules/eslint/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, + "license": "MIT" }, - "node_modules/esast-util-from-estree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", - "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "node_modules/eslint/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, "license": "MIT", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "devlop": "^1.0.0", - "estree-util-visit": "^2.0.0", - "unist-util-position-from-estree": "^2.0.0" + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esast-util-from-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", - "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", - "license": "MIT", + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@types/estree-jsx": "^1.0.0", - "acorn": "^8.0.0", - "esast-util-from-estree": "^2.0.0", - "vfile-message": "^4.0.0" + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/eslint/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, "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escape-goat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", - "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "node_modules/eslint/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, "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "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==", + "node_modules/eslint/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, "license": "MIT", "engines": { "node": ">=10" @@ -15214,17 +12709,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": ">=8.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -15240,6 +12740,29 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -15624,6 +13147,28 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "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, + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, "node_modules/fast-uri": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", @@ -15640,6 +13185,15 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -15692,6 +13246,19 @@ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", "license": "MIT" }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -15856,6 +13423,27 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, "node_modules/follow-redirects": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", @@ -15876,12 +13464,6 @@ } } }, - "node_modules/forge-std": { - "version": "1.9.4", - "resolved": "git+ssh://git@github.com/foundry-rs/forge-std.git#1eea5bae12ae557d589f9f0f0edae2faa47cb262", - "dev": true, - "license": "(Apache-2.0 OR MIT)" - }, "node_modules/form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -15951,13 +13533,6 @@ "node": ">=6 <7 || >=8" } }, - "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, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -16967,18 +14542,6 @@ "node": ">=12" } }, - "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==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "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", @@ -17386,6 +14949,21 @@ "node": ">=0.10.0" } }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -17534,6 +15112,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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, + "license": "MIT" + }, "node_modules/json-stable-stringify/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -17680,6 +15265,20 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -20681,6 +18280,15 @@ "multicast-dns": "cli.js" } }, + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/nanoid": { "version": "3.3.15", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", @@ -20705,6 +18313,13 @@ "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", "license": "MIT" }, + "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, + "license": "MIT" + }, "node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", @@ -21098,6 +18713,24 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/outdent": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", @@ -21105,6 +18738,54 @@ "dev": true, "license": "MIT" }, + "node_modules/ox": { + "version": "0.14.30", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.30.tgz", + "integrity": "sha512-LI11uu+8iiM1B3CLckgd++YF1a0A2k5wDoM9ZeQMiL21BOzQs6L//BLS6hb1HSEKCyycdDIQLsVQx9MjpcC0hA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.2.3", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", @@ -21527,16 +19208,6 @@ "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, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -23250,6 +20921,16 @@ "node": ">=6" } }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prettier": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", @@ -25659,6 +23340,55 @@ "node": ">=18" } }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tinypool": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", @@ -25744,6 +23474,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-dedent": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", @@ -25790,6 +23533,19 @@ "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, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -25845,6 +23601,45 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.64.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.64.0.tgz", + "integrity": "sha512-0qg+pDNMnqYzqH9AnNK+39tejHvsShUOUUoRUgtnTGE7QuMZhiFDnozq8nHJVq+Wae6NMLKNWLg5WmkcC/ndyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.64.0", + "@typescript-eslint/parser": "8.64.0", + "@typescript-eslint/typescript-estree": "8.64.0", + "@typescript-eslint/utils": "8.64.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/undici-types": { "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", @@ -26352,6 +24147,69 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/viem": { + "version": "2.55.2", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.55.2.tgz", + "integrity": "sha512-XlJeyNAZ96dQfOHlxLTK1FKgtWw/TtxENKNMBSBgxqALjiWiBWrFmSSzwwMivryKnBwkbt5E+90jSCLnVEilLA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.9.1", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.2.3", + "isows": "1.0.7", + "ox": "0.14.30", + "ws": "8.21.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/watchpack": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", @@ -26757,6 +24615,16 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "license": "MIT" }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -26842,6 +24710,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", "license": "MIT", + "peer": true, "engines": { "node": ">=8.3.0" }, diff --git a/package.json b/package.json index 039dd1c2..bde95c6a 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,12 @@ "compose@fmt": "forge fmt", "compose@check": "forge fmt --check && forge build --sizes && forge test -vvv", "compose@pack:check": "npm --workspace src run pack:check", + "cli@build": "npm --workspace cli run build", "cli@lint": "npm --workspace cli run lint", - "cli@test": "npm --workspace cli run test", "cli@link": "cd cli && npm link", "cli@check": "npm --workspace cli run check", "cli@pack:check": "npm --workspace cli run pack:check", - "check": "npm run compose@check && npm run compose@pack:check && npm run cli@check && npm run cli@pack:check", + "check": "npm run compose@check && npm run compose@pack:check && npm run cli@build && npm run cli@check && npm run cli@pack:check", "version-packages": "sh -c 'cp CHANGELOG.md src/CHANGELOG.md 2>/dev/null || true; changeset version; cp src/CHANGELOG.md CHANGELOG.md; cp CHANGELOG.md src/CHANGELOG.md'", "release": "changeset publish" }, From 942348d6cf6ac476c6aa10170b10b642ab279aac Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 16:54:56 -0400 Subject: [PATCH 02/11] refactor: update comments to use block comment style for consistency --- cli/src/templates/counter/CounterResetFacet.sol | 2 +- cli/src/templates/deploy/foundry-deploy.sol | 6 +++--- .../templates/examples/ERC20IdentifierCollisionError.sol | 8 +++++--- cli/src/templates/examples/ERC20MissingExportSelector.sol | 6 ++++-- .../templates/examples/ERC20SelectorCollisionError.sol | 8 +++++--- cli/src/templates/test/foundry-test.sol | 4 ++-- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/cli/src/templates/counter/CounterResetFacet.sol b/cli/src/templates/counter/CounterResetFacet.sol index ca67e419..ccda3042 100644 --- a/cli/src/templates/counter/CounterResetFacet.sol +++ b/cli/src/templates/counter/CounterResetFacet.sol @@ -5,7 +5,7 @@ pragma solidity >=0.8.30; * https://compose.diamonds */ -/// @custom:storage-location erc7201:counter +/** @custom:storage-location erc7201:counter */ contract CounterResetFacet { bytes32 constant STORAGE_POSITION = keccak256("counter"); diff --git a/cli/src/templates/deploy/foundry-deploy.sol b/cli/src/templates/deploy/foundry-deploy.sol index 64c93ec4..a38f5d5a 100644 --- a/cli/src/templates/deploy/foundry-deploy.sol +++ b/cli/src/templates/deploy/foundry-deploy.sol @@ -18,13 +18,13 @@ contract DeployScript is Script { address[] memory facets = new address[]({{FACET_COUNT}}); - // Base facet generation. + /* Base facet generation. */ {{BASE_LINES}} - // Library facet generation. + /* Library facet generation. */ {{LIBRARY_LINES}} - // Define diamond proxy. + /* Define diamond proxy. */ diamond = new Diamond(facets); console.log("Diamond:", address(diamond)); diff --git a/cli/src/templates/examples/ERC20IdentifierCollisionError.sol b/cli/src/templates/examples/ERC20IdentifierCollisionError.sol index be77e7f4..0ca5eabe 100644 --- a/cli/src/templates/examples/ERC20IdentifierCollisionError.sol +++ b/cli/src/templates/examples/ERC20IdentifierCollisionError.sol @@ -5,8 +5,10 @@ pragma solidity >=0.8.30; * https://compose.diamonds */ -// TEST FIXTURE: This facet intentionally has identifier collisions. -// Used by the CLI to validate that identifier collisions are detected. +/* + * TEST FIXTURE: This facet intentionally has identifier collisions. + * Used by the CLI to validate that identifier collisions are detected. + */ contract ERC20IdentifierCollisionError { bytes32 constant STORAGE_POSITION = keccak256("erc20.identifier"); @@ -23,7 +25,7 @@ contract ERC20IdentifierCollisionError { } } - // ERROR: Two functions with the same name but different signatures + /* ERROR: Two functions with the same name but different signatures */ function getValue() external view returns (uint256) { return getStorage().value; } diff --git a/cli/src/templates/examples/ERC20MissingExportSelector.sol b/cli/src/templates/examples/ERC20MissingExportSelector.sol index 5ddc5186..90d46255 100644 --- a/cli/src/templates/examples/ERC20MissingExportSelector.sol +++ b/cli/src/templates/examples/ERC20MissingExportSelector.sol @@ -5,8 +5,10 @@ pragma solidity >=0.8.30; * https://compose.diamonds */ -// TEST FIXTURE: This facet intentionally does NOT implement exportSelectors(). -// Used by the CLI to validate that missing exportSelectors() is detected. +/* + * TEST FIXTURE: This facet intentionally does NOT implement exportSelectors(). + * Used by the CLI to validate that missing exportSelectors() is detected. + */ contract ERC20MissingExportSelector { bytes32 constant STORAGE_POSITION = keccak256("erc20.missing"); diff --git a/cli/src/templates/examples/ERC20SelectorCollisionError.sol b/cli/src/templates/examples/ERC20SelectorCollisionError.sol index 7bcb235f..df72f4e5 100644 --- a/cli/src/templates/examples/ERC20SelectorCollisionError.sol +++ b/cli/src/templates/examples/ERC20SelectorCollisionError.sol @@ -5,8 +5,10 @@ pragma solidity >=0.8.30; * https://compose.diamonds */ -// TEST FIXTURE: This facet intentionally exports the same selector twice. -// Used by the CLI to validate that selector collisions are detected. +/* + * TEST FIXTURE: This facet intentionally exports the same selector twice. + * Used by the CLI to validate that selector collisions are detected. + */ contract ERC20SelectorCollisionError { bytes32 constant STORAGE_POSITION = keccak256("erc20.collision"); @@ -30,7 +32,7 @@ contract ERC20SelectorCollisionError { getStorage().value = _value; } - // ERROR: exportSelectors() exports this.getValue.selector twice + /* ERROR: exportSelectors() exports this.getValue.selector twice */ function exportSelectors() external pure returns (bytes memory) { return bytes.concat(this.getValue.selector, this.getValue.selector); } diff --git a/cli/src/templates/test/foundry-test.sol b/cli/src/templates/test/foundry-test.sol index afb772dd..7fcb0c25 100644 --- a/cli/src/templates/test/foundry-test.sol +++ b/cli/src/templates/test/foundry-test.sol @@ -15,10 +15,10 @@ contract DiamondTest is Test { function setUp() public { address[] memory facets = new address[]({{FACET_COUNT}}); - // Base facet generation. + /* Base facet generation. */ {{BASE_LINES}} - // Library facet generation. + /* Library facet generation. */ {{LIBRARY_LINES}} diamond = new Diamond(facets); From c21f2389510a154842565cce43dd320d7721fa7b Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 17:07:26 -0400 Subject: [PATCH 03/11] refactor: dynamic res for compose package path in CLI --- cli/src/utils/soliditySources.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/cli/src/utils/soliditySources.ts b/cli/src/utils/soliditySources.ts index 5214feb9..6245b383 100644 --- a/cli/src/utils/soliditySources.ts +++ b/cli/src/utils/soliditySources.ts @@ -2,9 +2,22 @@ import path from "node:path"; /** Prefix used to identify Compose package imports. */ export const COMPOSE_PACKAGE_PREFIX = "@perfect-abstractions/compose/"; -const CLI_COMPOSE_PATH = "./node_modules/@perfect-abstractions/compose/"; const LOCAL_TEMPLATE_PREFIX = "./src/templates/"; +/** + * Resolves the installed root directory of the `@perfect-abstractions/compose` + * package using Node module resolution. + * + * This correctly handles monorepo workspaces where npm may hoist the + * dependency to the root `node_modules/` instead of the CLI's own + * `node_modules/`. It also works for global installs and any other + * layout where the CLI's dependencies are resolved by Node. + */ +function getComposePackageRoot(): string { + const pkgJson = require.resolve("@perfect-abstractions/compose/package.json"); + return path.dirname(pkgJson); +} + /** * Identifies catalog paths that should resolve through the installed Compose package. * @@ -46,7 +59,8 @@ export function toComposePackagePath(sourcePath: string): string { /** * Resolves a catalog Solidity path to a local file the CLI can read for validation. - * Package paths resolve from the CLI's own `node_modules/@perfect-abstractions/compose/`. + * Package paths resolve via Node module resolution from the CLI's installed + * `@perfect-abstractions/compose` dependency. * Local paths resolve from the CLI's `src/templates/` directory. * * @param sourcePath - The catalog source path to resolve. @@ -54,7 +68,7 @@ export function toComposePackagePath(sourcePath: string): string { */ export function resolveCatalogSourceForRead(sourcePath: string): string { if (isComposePackagePath(sourcePath)) { - return path.resolve(process.cwd(), CLI_COMPOSE_PATH, composePackageSubpath(sourcePath)); + return path.join(getComposePackageRoot(), composePackageSubpath(sourcePath)); } return path.resolve(process.cwd(), sourcePath); From 738c354ea79f0d399bcd64fc507bd6c4b22a8219 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 17:15:22 -0400 Subject: [PATCH 04/11] fix: install generated project deps in ci --- .github/workflows/cli.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index c06a544a..a46a6700 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -84,8 +84,7 @@ jobs: --framework foundry \ --base counter \ --ownership owner \ - --yes \ - --no-install-deps + --yes cd ci-foundry forge build @@ -98,8 +97,7 @@ jobs: --toolbox ethers \ --base counter \ --ownership owner \ - --yes \ - --no-install-deps + --yes cd ci-hardhat npx hardhat compile From 74cd24892fc3fe03699a7b14b44ea84d3469c69a Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 17:20:26 -0400 Subject: [PATCH 05/11] remove smoketest on node 20 (unsupported by Hardhat 3) --- .github/workflows/cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index a46a6700..cbaba96d 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -46,7 +46,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [20.x, 22.x, 24.x] + node-version: [22.x, 24.x] needs: lint env: FOUNDRY_PROFILE: ci From 66ab30398016c97a24df852247014800bbe1fe21 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 17:42:58 -0400 Subject: [PATCH 06/11] feat: add 'catalog' command to list available project base --- cli/README.md | 5 ++ cli/package.json | 2 +- cli/src/comander.ts | 4 ++ cli/src/modules/pipelineBuilder/module.ts | 8 +++ cli/src/modules/terminalOutput/module.ts | 59 ++++++++++++++++++----- cli/src/pipelines/catalogPipeline.ts | 17 +++++++ 6 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 cli/src/pipelines/catalogPipeline.ts diff --git a/cli/README.md b/cli/README.md index ae40d6aa..05a773b8 100644 --- a/cli/README.md +++ b/cli/README.md @@ -19,6 +19,7 @@ This starts an interactive flow to scaffold a new diamond project with: ```bash compose init [options] +compose catalog compose info compose validate compose --version | -v @@ -44,6 +45,10 @@ Scaffold a new Compose diamond project. When `--yes` is not provided, `compose init` will prompt for any values you omit. +### `compose catalog` + +List all available bases for init. Displays bases grouped by type (Features, Access Control) with their required and optional facet counts. + ### `compose info` Display a summary of the local project: diff --git a/cli/package.json b/cli/package.json index 0ba1062c..89f93c15 100644 --- a/cli/package.json +++ b/cli/package.json @@ -28,8 +28,8 @@ "LICENSE.md" ], "dependencies": { - "@perfect-abstractions/compose": "0.0.4", "@inquirer/prompts": "^8.5.2", + "@perfect-abstractions/compose": "0.0.4", "commander": "^13.1.0", "fs-extra": "^11.3.3", "inquirer": "^13.3.0", diff --git a/cli/src/comander.ts b/cli/src/comander.ts index 690e4155..8c448436 100644 --- a/cli/src/comander.ts +++ b/cli/src/comander.ts @@ -40,6 +40,10 @@ export function buildProgram(): Command { .command("info") .description("Display a summary of the local project") + program + .command("catalog") + .description("List all available bases in the Compose Catalog") + return program; } diff --git a/cli/src/modules/pipelineBuilder/module.ts b/cli/src/modules/pipelineBuilder/module.ts index 6a2caad5..f98d4cc2 100644 --- a/cli/src/modules/pipelineBuilder/module.ts +++ b/cli/src/modules/pipelineBuilder/module.ts @@ -1,6 +1,7 @@ import { ComposeContext } from "../../context/types"; import { InitPipeline } from "../../pipelines/initPipeline"; import { InfoPipeline } from "../../pipelines/infoPipeline"; +import { CatalogPipeline } from "../../pipelines/catalogPipeline"; /** * Pipeline builder module that routes CLI commands to their corresponding pipelines. @@ -43,6 +44,13 @@ export const PipelineBuilderModule = { error: null, }; return InfoPipeline.execute(ctx); + case "catalog": + ctx.state.commandSelected = { + success: true, + result: { command: ctx.param.command }, + error: null, + }; + return CatalogPipeline.execute(ctx); default: ctx.state.commandRouting = { success: false, diff --git a/cli/src/modules/terminalOutput/module.ts b/cli/src/modules/terminalOutput/module.ts index b2bc04da..f3eb487a 100644 --- a/cli/src/modules/terminalOutput/module.ts +++ b/cli/src/modules/terminalOutput/module.ts @@ -1,5 +1,5 @@ import { ComposeContext } from "../../context/types"; -import { BasesCatalog } from "../config/types"; +import { BasesCatalog, BaseDefinition } from "../config/types"; import { cyan, dim, green, red, yellow } from "../../utils/terminal"; import { COMPOSE_HEADER, COMPOSE_DOCS_URL } from "../../utils/metadata"; import { @@ -176,10 +176,10 @@ export const TerminalOutputModule = { }, /** - * Displays available Compose bases with their required and optional facets. + * Displays available Compose bases grouped by type with facet counts. * - * Reads the bases catalog from `ctx.config.bases` and prints each feature - * with its label, required facets, and optional facets. + * Reads the bases catalog from `ctx.config.bases` and prints each base + * grouped into Features and Access Control sections. * * @param ctx - The compose context with the loaded bases catalog. */ @@ -187,17 +187,52 @@ export const TerminalOutputModule = { const catalog = ctx.config.bases as BasesCatalog; const features = catalog.features; - console.log("\nAvailable Compose bases:\n"); + const featureBases: [string, BaseDefinition][] = []; + const accessBases: [string, BaseDefinition][] = []; - Object.entries(features).forEach(([key, definition]) => { - console.log(`${definition.label} (${key})`); - console.log(` Required: ${Object.keys(definition.required).join(", ") || "(none)"}`); - if (Object.keys(definition.optional).length > 0) { - console.log(` Optional: ${Object.keys(definition.optional).join(", ")}`); + for (const [key, definition] of Object.entries(features)) { + if (definition.access) { + accessBases.push([key, definition]); + } else { + featureBases.push([key, definition]); + } + } + + const maxIdLen = Math.max( + ...featureBases.map(([k]) => k.length), + ...accessBases.map(([k]) => k.length), + ); + + console.log(`\n${cyan("Compose Catalog")}\n`); + + if (featureBases.length > 0) { + console.log(dim(" Features")); + console.log(dim(" " + "─".repeat(maxIdLen + 28))); + for (const [key, definition] of featureBases) { + const required = Object.keys(definition.required).length; + const optional = Object.keys(definition.optional).length; + const id = key.padEnd(maxIdLen + 2); + const label = dim(definition.label.padEnd(22)); + const counts = `${green(`${required} required`)}, ${yellow(`${optional} optional`)}`; + console.log(` ${cyan(id)}${label}${counts}`); } console.log(""); - }); + } + + if (accessBases.length > 0) { + console.log(dim(" Access Control")); + console.log(dim(" " + "─".repeat(maxIdLen + 28))); + for (const [key, definition] of accessBases) { + const required = Object.keys(definition.required).length; + const optional = Object.keys(definition.optional).length; + const id = key.padEnd(maxIdLen + 2); + const label = dim(definition.label.padEnd(22)); + const counts = `${green(`${required} required`)}, ${yellow(`${optional} optional`)}`; + console.log(` ${cyan(id)}${label}${counts}`); + } + console.log(""); + } - console.log("\nTo select a base for your project, use --base \n"); + console.log(dim(" Use --base with compose init\n")); }, }; \ No newline at end of file diff --git a/cli/src/pipelines/catalogPipeline.ts b/cli/src/pipelines/catalogPipeline.ts new file mode 100644 index 00000000..d1acec77 --- /dev/null +++ b/cli/src/pipelines/catalogPipeline.ts @@ -0,0 +1,17 @@ +import { ComposeContext } from "../context/types"; +import { ConfigModule } from "../modules/config/module"; +import { TerminalOutputModule } from "../modules/terminalOutput/module"; + +/** + * Catalog Pipeline. + * + * Loads the bases catalog and displays all available bases + * with their required and optional facets. + */ +export const CatalogPipeline = { + async execute(ctx: ComposeContext): Promise { + ctx = await ConfigModule.loadBasesCatalog(ctx); + TerminalOutputModule.showTemplates(ctx); + return ctx; + }, +}; From 70457b4102f1bc70c85e7ec99809403dcf79c671 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 18:06:20 -0400 Subject: [PATCH 07/11] refactor: enhance project info display --- cli/src/modules/info/output.ts | 136 ++++++++++++++------------------- 1 file changed, 58 insertions(+), 78 deletions(-) diff --git a/cli/src/modules/info/output.ts b/cli/src/modules/info/output.ts index 7f8f6d57..72045cdc 100644 --- a/cli/src/modules/info/output.ts +++ b/cli/src/modules/info/output.ts @@ -1,7 +1,12 @@ import { ComposeContext } from "../../context/types"; -import { cyan, dim, green, yellow } from "../../utils/terminal"; +import { blue, cyan, dim, green, yellow } from "../../utils/terminal"; import { ComposeProjectInfo, DiamondInfo, FacetInfo, StorageSlotInfo } from "./types"; +const TREE_BRANCH = "├── "; +const TREE_LAST = "└── "; +const TREE_PIPE = "│ "; +const TREE_SPACE = " "; + /** * Formats and displays the project info summary to the console. * @@ -16,53 +21,49 @@ export function showInfo(ctx: ComposeContext): void { const info = projectState.result; - // Header - console.log(cyan(`Project: ${info.project}`)); - console.log(dim(`Framework: ${info.framework}`)); + console.log(cyan(info.project)); + console.log(dim(`${info.framework} · compose ${info.composeVersion}`)); console.log(""); if (info.diamonds.length === 0) { - console.log(yellow(" No diamonds defined in compose.json")); + console.log(dim(" No diamonds defined")); + console.log(""); return; } - // Diamonds for (const diamond of info.diamonds) { printDiamond(diamond); + console.log(""); } - // Warnings if (info.warnings.length > 0) { - console.log(yellow("\nWarnings:")); for (const warning of info.warnings) { - console.log(yellow(` ${warning}`)); + console.log(yellow(`⚠ ${warning}`)); } + console.log(""); } - - console.log(""); } /** - * Prints a single diamond's summary to the console. + * Prints a single diamond and its facets to the console. * * @param diamond - The diamond info to print. */ function printDiamond(diamond: DiamondInfo): void { - console.log(cyan(`Diamond: ${diamond.name}`)); - console.log(dim(` Contract: ${diamond.contract}`)); - console.log(""); + console.log(blue(`◇ ${diamond.name}`)); - if (diamond.facets.length === 0) { - console.log(dim(" No facets defined")); - console.log(""); + const facetCount = diamond.facets.length; + const label = facetCount === 1 ? "facet" : "facets"; + console.log(dim(`${TREE_PIPE}${diamond.contract} · ${facetCount} ${label}`)); + console.log(dim(TREE_PIPE)); + + if (facetCount === 0) { return; } - console.log(` Facets (${diamond.facets.length}):`); - console.log(""); - - for (const facet of diamond.facets) { - printFacet(facet); + for (let i = 0; i < facetCount; i++) { + const isLast = i === facetCount - 1; + printFacet(diamond.facets[i], isLast, TREE_PIPE); } } @@ -70,77 +71,56 @@ function printDiamond(diamond: DiamondInfo): void { * Prints a single facet's summary to the console. * * @param facet - The facet info to print. + * @param isLast - Whether this is the last facet in the diamond. + * @param prefix - The tree continuation prefix from the parent. */ -function printFacet(facet: FacetInfo): void { - console.log(green(` ${facet.name}`)); - printSource(facet); - printSelectors(facet); - printStorageSlots(facet); - console.log(""); -} +function printFacet(facet: FacetInfo, isLast: boolean, prefix: string): void { + const branch = isLast ? TREE_LAST : TREE_BRANCH; + const childPrefix = prefix + (isLast ? TREE_SPACE : TREE_PIPE); -/** - * Prints the facet source type and path to the console. - * - * @param facet - The facet info to print source for. - */ -function printSource(facet: FacetInfo): void { - switch (facet.source) { - case "local": - console.log(dim(` Source: local (${facet.contract})`)); - break; - case "package": - console.log(dim(` Source: package (${facet.package ?? "unknown"})`)); - break; - case "registry": - console.log(dim(` Source: registry`)); - break; - default: - console.log(dim(` Source: ${facet.source}`)); - } -} + console.log(dim(`${prefix}${branch}`) + green(facet.name)); -/** - * Prints the facet's exported selectors to the console. - * - * @param facet - The facet info to print selectors for. - */ -function printSelectors(facet: FacetInfo): void { - if (facet.selectors.length === 0) { - console.log(dim(" Selectors: (none)")); - return; + const sourceLine = formatSource(facet); + if (sourceLine) { + console.log(dim(childPrefix) + sourceLine); } - console.log(" Selectors:"); for (const selector of facet.selectors) { - console.log(` ${selector}`); + console.log(dim(childPrefix) + selector); + } + + for (const slot of facet.storageSlots) { + console.log(dim(childPrefix) + formatStorageSlot(slot)); } } /** - * Prints the facet's storage slot annotations to the console. + * Formats a facet's source type and path. * - * @param facet - The facet info to print storage slots for. + * @param facet - The facet to format source for. + * @returns The formatted source string, or empty if unknown. */ -function printStorageSlots(facet: FacetInfo): void { - if (facet.storageSlots.length === 0) { - return; - } - - console.log(" Storage:"); - for (const slot of facet.storageSlots) { - printStorageSlot(slot); +function formatSource(facet: FacetInfo): string { + switch (facet.source) { + case "local": + return dim(`local ${facet.contract}`); + case "package": + return dim(`package ${facet.package ?? "unknown"}`); + case "registry": + return dim("registry"); + default: + return dim(facet.source); } } /** - * Prints a single storage slot annotation to the console. + * Formats a single storage slot annotation. * - * @param slot - The storage slot info to print. + * @param slot - The storage slot info to format. + * @returns The formatted storage slot string. */ -function printStorageSlot(slot: StorageSlotInfo): void { - const structLabel = slot.structName ? ` (${slot.structName})` : ""; - const layoutStr = slot.layout.length > 0 ? ` [${slot.layout.join(", ")}]` : ""; - - console.log(` ${slot.slot}${structLabel}${layoutStr}`); +function formatStorageSlot(slot: StorageSlotInfo): string { + const structLabel = slot.structName ? ` ${slot.structName}` : ""; + const layoutStr = slot.layout.length > 0 ? ` ${dim(`[${slot.layout.join(", ")}]`)}` : ""; + return dim(slot.slot) + structLabel + layoutStr; } From 30063c0887da21ab5d2da004dbb3a27e85405420 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Tue, 14 Jul 2026 18:38:39 -0400 Subject: [PATCH 08/11] improve: facet display formatting in project info output --- cli/src/modules/info/output.ts | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/cli/src/modules/info/output.ts b/cli/src/modules/info/output.ts index 72045cdc..0bc8f2b2 100644 --- a/cli/src/modules/info/output.ts +++ b/cli/src/modules/info/output.ts @@ -77,21 +77,18 @@ function printDiamond(diamond: DiamondInfo): void { function printFacet(facet: FacetInfo, isLast: boolean, prefix: string): void { const branch = isLast ? TREE_LAST : TREE_BRANCH; const childPrefix = prefix + (isLast ? TREE_SPACE : TREE_PIPE); - - console.log(dim(`${prefix}${branch}`) + green(facet.name)); - const sourceLine = formatSource(facet); - if (sourceLine) { - console.log(dim(childPrefix) + sourceLine); - } - for (const selector of facet.selectors) { - console.log(dim(childPrefix) + selector); - } + console.log(dim(`${prefix}${branch}`) + green(facet.name) + (sourceLine ? " " + sourceLine : "")); for (const slot of facet.storageSlots) { console.log(dim(childPrefix) + formatStorageSlot(slot)); } + + for (const selector of facet.selectors) { + console.log(dim(childPrefix) + "• " + selector); + } + console.log(dim(childPrefix)); } /** @@ -103,9 +100,9 @@ function printFacet(facet: FacetInfo, isLast: boolean, prefix: string): void { function formatSource(facet: FacetInfo): string { switch (facet.source) { case "local": - return dim(`local ${facet.contract}`); + return dim(`${facet.contract}`); case "package": - return dim(`package ${facet.package ?? "unknown"}`); + return dim(`${facet.package ?? "unknown package"}`); case "registry": return dim("registry"); default: @@ -122,5 +119,5 @@ function formatSource(facet: FacetInfo): string { function formatStorageSlot(slot: StorageSlotInfo): string { const structLabel = slot.structName ? ` ${slot.structName}` : ""; const layoutStr = slot.layout.length > 0 ? ` ${dim(`[${slot.layout.join(", ")}]`)}` : ""; - return dim(slot.slot) + structLabel + layoutStr; + return yellow(slot.slot) + structLabel + layoutStr; } From 8bcf109d2cb7d014392551e660cb3a675e5e015e Mon Sep 17 00:00:00 2001 From: maxnorm Date: Wed, 15 Jul 2026 21:16:32 -0400 Subject: [PATCH 09/11] refactor: update template path resolution to use CLI_ROOT --- cli/src/adapters/foundryAdapter.ts | 3 ++- cli/src/adapters/hardhatAdapter.ts | 3 ++- cli/src/modules/config/module.ts | 6 +++--- cli/src/utils/cliRoot.ts | 12 ++++++++++++ cli/src/utils/codegen.ts | 3 ++- cli/src/utils/soliditySources.ts | 3 ++- 6 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 cli/src/utils/cliRoot.ts diff --git a/cli/src/adapters/foundryAdapter.ts b/cli/src/adapters/foundryAdapter.ts index fe7bc9aa..184ecb1f 100644 --- a/cli/src/adapters/foundryAdapter.ts +++ b/cli/src/adapters/foundryAdapter.ts @@ -5,6 +5,7 @@ import { ConfigOptions, IFrameworkAdapter } from "./interface/IFrameworkAdapter" import { writeFileIfMissing } from "../utils/files"; import { runCommand } from "../utils/exec"; import { resolveCatalogSourceForRead } from "../utils/soliditySources"; +import { CLI_ROOT } from "../utils/cliRoot"; function ensureTomlSectionSettings( content: string, @@ -96,7 +97,7 @@ const adapter: IFrameworkAdapter = { let readme: string; try { - const templatePath = path.resolve(process.cwd(), "src/templates/readme/foundry-readme.md"); + const templatePath = path.resolve(CLI_ROOT, "src/templates/readme/foundry-readme.md"); const template = await fs.readFile(templatePath, "utf8"); readme = template.replace(/\{\{PROJECT_NAME\}\}/g, opts.projectName); } catch { diff --git a/cli/src/adapters/hardhatAdapter.ts b/cli/src/adapters/hardhatAdapter.ts index 3c156658..9583476f 100644 --- a/cli/src/adapters/hardhatAdapter.ts +++ b/cli/src/adapters/hardhatAdapter.ts @@ -6,6 +6,7 @@ import { writeFileIfMissing } from "../utils/files"; import { runCommand } from "../utils/exec"; import { isComposePackagePath, resolveCatalogSourceForRead } from "../utils/soliditySources"; import { getSelectedFacets } from "../modules/scaffolding/module"; +import { CLI_ROOT } from "../utils/cliRoot"; /** Framework adapter for Hardhat-based Diamond projects. */ const adapter: IFrameworkAdapter = { @@ -146,7 +147,7 @@ dist/ let readme: string; try { - const templatePath = path.resolve(process.cwd(), "src/templates/readme/hardhat-readme.md"); + const templatePath = path.resolve(CLI_ROOT, "src/templates/readme/hardhat-readme.md"); const template = await fs.readFile(templatePath, "utf8"); readme = template.replace(/\{\{PROJECT_NAME\}\}/g, opts.projectName); } catch { diff --git a/cli/src/modules/config/module.ts b/cli/src/modules/config/module.ts index 662c090a..a02b0bed 100644 --- a/cli/src/modules/config/module.ts +++ b/cli/src/modules/config/module.ts @@ -3,6 +3,7 @@ import path from "node:path"; import { ComposeContext } from "../../context/types"; import { BasesCatalog, BaseDefinition, BaseManifest } from "./types"; import { sortBaseFeatures } from "./catalog"; +import { CLI_ROOT } from "../../utils/cliRoot"; export { EMPTY_BASE, getDiamondCompilerVersion } from "./catalog"; export { resolveCatalogSelection, getAccessBases, getAvailableLibraryFacets, validateGroupedAccessFlags } from "./selection"; @@ -26,12 +27,11 @@ export const ConfigModule = { * The catalog is stored on `ctx.config.bases` and a summary is written to * `ctx.state.config`. * - * @param ctx - The compose context (must have `process.cwd()` pointing to a - * directory containing a `bases/` folder). + * @param ctx - The compose context. * @returns The context with the loaded bases catalog. */ async loadBasesCatalog(ctx: ComposeContext): Promise { - const basesRoot = path.resolve(process.cwd(), "bases"); + const basesRoot = path.resolve(CLI_ROOT, "bases"); const entries = await fs.readdir(basesRoot, { withFileTypes: true }); const globals: BasesCatalog["globals"] = {}; diff --git a/cli/src/utils/cliRoot.ts b/cli/src/utils/cliRoot.ts new file mode 100644 index 00000000..7b358846 --- /dev/null +++ b/cli/src/utils/cliRoot.ts @@ -0,0 +1,12 @@ +import path from "node:path"; + +/** + * Absolute path to the CLI package root. + * + * Resolves from this compiled file's location (e.g. `dist/utils/cliRoot.js`) + * up two levels to the package root, where shipped assets like `bases/` and + * `src/templates/` live. + * + * Using this constant ensures the CLI can locate its own assets when installed as a package + */ +export const CLI_ROOT = path.resolve(__dirname, "..", ".."); diff --git a/cli/src/utils/codegen.ts b/cli/src/utils/codegen.ts index 239e0dd7..f9a171fa 100644 --- a/cli/src/utils/codegen.ts +++ b/cli/src/utils/codegen.ts @@ -1,5 +1,6 @@ import fs from "node:fs/promises"; import path from "node:path"; +import { CLI_ROOT } from "./cliRoot"; /** * Loads a template file from the templates directory. @@ -9,6 +10,6 @@ import path from "node:path"; * @returns The template content as a string. */ export async function loadTemplate(subdir: string, name: string): Promise { - const templatePath = path.resolve(process.cwd(), "src/templates", subdir, name); + const templatePath = path.resolve(CLI_ROOT, "src/templates", subdir, name); return fs.readFile(templatePath, "utf8"); } diff --git a/cli/src/utils/soliditySources.ts b/cli/src/utils/soliditySources.ts index 6245b383..d21c9ae8 100644 --- a/cli/src/utils/soliditySources.ts +++ b/cli/src/utils/soliditySources.ts @@ -1,4 +1,5 @@ import path from "node:path"; +import { CLI_ROOT } from "./cliRoot"; /** Prefix used to identify Compose package imports. */ export const COMPOSE_PACKAGE_PREFIX = "@perfect-abstractions/compose/"; @@ -71,7 +72,7 @@ export function resolveCatalogSourceForRead(sourcePath: string): string { return path.join(getComposePackageRoot(), composePackageSubpath(sourcePath)); } - return path.resolve(process.cwd(), sourcePath); + return path.resolve(CLI_ROOT, sourcePath); } /** From c992eb8ab4e5959ad506347d99cc55eae302cd01 Mon Sep 17 00:00:00 2001 From: maxnorm Date: Wed, 15 Jul 2026 21:53:25 -0400 Subject: [PATCH 10/11] feat: add project name validation --- .../{framework-deps.ts => frameworkDeps.ts} | 0 cli/src/modules/init/module.ts | 15 +++- cli/src/modules/init/projectNameValidation.ts | 77 +++++++++++++++++++ cli/src/modules/init/types.ts | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) rename cli/src/modules/init/{framework-deps.ts => frameworkDeps.ts} (100%) create mode 100644 cli/src/modules/init/projectNameValidation.ts diff --git a/cli/src/modules/init/framework-deps.ts b/cli/src/modules/init/frameworkDeps.ts similarity index 100% rename from cli/src/modules/init/framework-deps.ts rename to cli/src/modules/init/frameworkDeps.ts diff --git a/cli/src/modules/init/module.ts b/cli/src/modules/init/module.ts index 24dcb8aa..7f95e8ab 100644 --- a/cli/src/modules/init/module.ts +++ b/cli/src/modules/init/module.ts @@ -17,9 +17,10 @@ import { selectTheme, toFacetChoices, } from "./prompts"; -import { getFrameworkDependencies } from "./framework-deps"; +import { getFrameworkDependencies } from "./frameworkDeps"; import { resolveAccessFlags } from "./flags"; import { splitCommaSeparated } from "../../utils/strings"; +import { validateProjectName, validateProjectNameWithFolder } from "./projectNameValidation"; import { TerminalOutputModule } from "../terminalOutput/module"; /** @@ -92,6 +93,10 @@ export const InitModule = { ); ctx.param.projectName = ctx.param.projectName ?? "my-diamond"; + const projectNameValidation = validateProjectName(String(ctx.param.projectName)); + if (projectNameValidation !== true) { + throw new Error(projectNameValidation); + } ctx.param.framework = framework; ctx.param.base = baseKey; ctx.param.libraries = selectedLibraries; @@ -136,11 +141,19 @@ export const InitModule = { const catalog = ctx.config.bases as BasesCatalog; if (!ctx.param.projectName) { + const outDir = String(ctx.param.outDir ?? process.cwd()); + const projectName = await input({ message: "Enter project name:", default: "my-diamond", + validate: (name) => validateProjectNameWithFolder(name, outDir), }); ctx.param.projectName = projectName; + } else { + const projectNameValidation = validateProjectName(String(ctx.param.projectName)); + if (projectNameValidation !== true) { + throw new Error(projectNameValidation); + } } const featureChoices = [ diff --git a/cli/src/modules/init/projectNameValidation.ts b/cli/src/modules/init/projectNameValidation.ts new file mode 100644 index 00000000..a6ed1f75 --- /dev/null +++ b/cli/src/modules/init/projectNameValidation.ts @@ -0,0 +1,77 @@ +import path from "node:path"; +import { pathExists, isDirectoryEmpty } from "../../utils/files"; + +const INVALID_PROJECT_NAME_CHARS = /[\\/:"*?<>|]/; + +const PROJECT_NAME_MAX_LENGTH = 210; + +/** + * Validates a project name string for filesystem safety and naming conventions. + * + * Checks for invalid characters, length limits, proper starting characters, + * and ensures the name follows standard project naming conventions. + * + * @param name - The project name to validate. + * @returns `true` if valid, or an error message string if invalid. + */ +export function validateProjectName(name: string): true | string { + const trimmed = name.trim(); + + if (!trimmed) { + return "Project name cannot be empty."; + } + + if (trimmed.length > PROJECT_NAME_MAX_LENGTH) { + return `Project name must be at most ${PROJECT_NAME_MAX_LENGTH} characters.`; + } + + if (trimmed.startsWith(".") || trimmed.startsWith("_")) { + return "Project name must not start with '.' or '_'."; + } + + if (INVALID_PROJECT_NAME_CHARS.test(trimmed)) { + return "Project name contains invalid characters (\\ / : * ? \" < > |)."; + } + + if (/\s/.test(trimmed)) { + return "Project name must not contain spaces."; + } + + if (!/^[a-zA-Z0-9]/.test(trimmed)) { + return "Project name must start with a letter or digit."; + } + + if (!/^[a-zA-Z0-9._-]+$/.test(trimmed)) { + return "Project name may only contain letters, digits, hyphens, underscores, or dots."; + } + + return true; +} + +/** + * Validates a project name and checks if the target directory is available. + * + * Combines string validation with filesystem checks to ensure the project name + * is valid and the target directory either doesn't exist or is empty (ignoring .git). + * + * @param name - The project name to validate. + * @param outDir - The output directory where the project will be created. + * @returns Promise resolving to `true` if valid, or an error message string if invalid. + */ +export async function validateProjectNameWithFolder(name: string, outDir: string): Promise { + const stringValidation = validateProjectName(name); + if (stringValidation !== true) { + return stringValidation; + } + + const projectRoot = path.resolve(outDir, name); + const exists = await pathExists(projectRoot); + if (exists) { + const isEmpty = await isDirectoryEmpty(projectRoot, [".git"]); + if (!isEmpty) { + return `Target directory is not empty: ${projectRoot}`; + } + } + + return true; +} diff --git a/cli/src/modules/init/types.ts b/cli/src/modules/init/types.ts index 97d065f4..f9591ff1 100644 --- a/cli/src/modules/init/types.ts +++ b/cli/src/modules/init/types.ts @@ -37,6 +37,7 @@ export type PromptApi = { input: (config: { message: string; default?: string; + validate?: (value: string) => boolean | string | Promise; theme?: { prefix?: string | { idle?: string; done?: string }; }; From c902b8bb086ad73e267b384641e7d1345a26463e Mon Sep 17 00:00:00 2001 From: maxnorm Date: Thu, 16 Jul 2026 09:26:53 -0400 Subject: [PATCH 11/11] refactor: move outputs to specific modules, fix module helpers export --- cli/src/adapters/hardhatAdapter.ts | 4 +- cli/src/modules/catalog/module.ts | 5 + cli/src/modules/catalog/output.ts | 64 +++++ cli/src/modules/config/module.ts | 12 +- cli/src/modules/deployGeneration/model.ts | 4 +- cli/src/modules/diamondGeneration/model.ts | 12 +- cli/src/modules/info/scanner.ts | 4 +- cli/src/modules/init/module.ts | 26 +- cli/src/modules/init/output.ts | 74 ++++++ cli/src/modules/scaffolding/facetSelection.ts | 4 +- cli/src/modules/scaffolding/module.ts | 7 +- cli/src/modules/terminalOutput/module.ts | 238 ------------------ cli/src/modules/validation/module.ts | 10 +- cli/src/modules/validation/output.ts | 93 +++++++ cli/src/pipelines/catalogPipeline.ts | 4 +- cli/src/pipelines/initPipeline.ts | 18 +- 16 files changed, 290 insertions(+), 289 deletions(-) create mode 100644 cli/src/modules/catalog/module.ts create mode 100644 cli/src/modules/catalog/output.ts create mode 100644 cli/src/modules/init/output.ts delete mode 100644 cli/src/modules/terminalOutput/module.ts create mode 100644 cli/src/modules/validation/output.ts diff --git a/cli/src/adapters/hardhatAdapter.ts b/cli/src/adapters/hardhatAdapter.ts index 9583476f..bab706bd 100644 --- a/cli/src/adapters/hardhatAdapter.ts +++ b/cli/src/adapters/hardhatAdapter.ts @@ -5,7 +5,7 @@ import { ConfigOptions, IFrameworkAdapter } from "./interface/IFrameworkAdapter" import { writeFileIfMissing } from "../utils/files"; import { runCommand } from "../utils/exec"; import { isComposePackagePath, resolveCatalogSourceForRead } from "../utils/soliditySources"; -import { getSelectedFacets } from "../modules/scaffolding/module"; +import { ScaffoldingModule } from "../modules/scaffolding/module"; import { CLI_ROOT } from "../utils/cliRoot"; /** Framework adapter for Hardhat-based Diamond projects. */ @@ -67,7 +67,7 @@ const adapter: IFrameworkAdapter = { async writeConfig(ctx: ComposeContext, opts: ConfigOptions): Promise { const root = String(ctx.param.projectRoot ?? ""); const toolbox = String(ctx.param.toolbox ?? "ethers"); - const selectedFacets = getSelectedFacets(ctx); + const selectedFacets = ScaffoldingModule.getSelectedFacets(ctx); const packageFacetPaths = selectedFacets .map((facet) => facet.entry.path) .filter(isComposePackagePath); diff --git a/cli/src/modules/catalog/module.ts b/cli/src/modules/catalog/module.ts new file mode 100644 index 00000000..b0d93ff3 --- /dev/null +++ b/cli/src/modules/catalog/module.ts @@ -0,0 +1,5 @@ +import { showTemplates } from "./output"; + +export const CatalogModule = { + showTemplates, +}; diff --git a/cli/src/modules/catalog/output.ts b/cli/src/modules/catalog/output.ts new file mode 100644 index 00000000..ade98629 --- /dev/null +++ b/cli/src/modules/catalog/output.ts @@ -0,0 +1,64 @@ +import { ComposeContext } from "../../context/types"; +import { BasesCatalog, BaseDefinition } from "../config/types"; +import { cyan, dim, green, yellow } from "../../utils/terminal"; + +/** + * Displays available Compose bases grouped by type with facet counts. + * + * Reads the bases catalog from `ctx.config.bases` and prints each base + * grouped into Features and Access Control sections. + * + * @param ctx - The compose context with the loaded bases catalog. + */ +export function showTemplates(ctx: ComposeContext): void { + const catalog = ctx.config.bases as BasesCatalog; + const features = catalog.features; + + const featureBases: [string, BaseDefinition][] = []; + const accessBases: [string, BaseDefinition][] = []; + + for (const [key, definition] of Object.entries(features)) { + if (definition.access) { + accessBases.push([key, definition]); + } else { + featureBases.push([key, definition]); + } + } + + const maxIdLen = Math.max( + ...featureBases.map(([k]) => k.length), + ...accessBases.map(([k]) => k.length), + ); + + console.log(`\n${cyan("Compose Catalog")}\n`); + + if (featureBases.length > 0) { + console.log(dim(" Features")); + console.log(dim(" " + "─".repeat(maxIdLen + 28))); + for (const [key, definition] of featureBases) { + const required = Object.keys(definition.required).length; + const optional = Object.keys(definition.optional).length; + const id = key.padEnd(maxIdLen + 2); + const label = dim(definition.label.padEnd(22)); + const counts = `${green(`${required} required`)}, ${yellow(`${optional} optional`)}`; + console.log(` ${cyan(id)}${label}${counts}`); + } + console.log(""); + } + + if (accessBases.length > 0) { + console.log(dim(" Access Control")); + console.log(dim(" " + "─".repeat(maxIdLen + 28))); + for (const [key, definition] of accessBases) { + const required = Object.keys(definition.required).length; + const optional = Object.keys(definition.optional).length; + const id = key.padEnd(maxIdLen + 2); + const label = dim(definition.label.padEnd(22)); + const counts = `${green(`${required} required`)}, ${yellow(`${optional} optional`)}`; + console.log(` ${cyan(id)}${label}${counts}`); + } + console.log(""); + } + + console.log(dim(" Use --base with compose init\n")); +} diff --git a/cli/src/modules/config/module.ts b/cli/src/modules/config/module.ts index a02b0bed..db173591 100644 --- a/cli/src/modules/config/module.ts +++ b/cli/src/modules/config/module.ts @@ -2,12 +2,10 @@ import fs from "node:fs/promises"; import path from "node:path"; import { ComposeContext } from "../../context/types"; import { BasesCatalog, BaseDefinition, BaseManifest } from "./types"; -import { sortBaseFeatures } from "./catalog"; +import { sortBaseFeatures, EMPTY_BASE, getDiamondCompilerVersion } from "./catalog"; +import { resolveCatalogSelection, getAccessBases, getAvailableLibraryFacets, validateGroupedAccessFlags } from "./selection"; import { CLI_ROOT } from "../../utils/cliRoot"; -export { EMPTY_BASE, getDiamondCompilerVersion } from "./catalog"; -export { resolveCatalogSelection, getAccessBases, getAvailableLibraryFacets, validateGroupedAccessFlags } from "./selection"; - /** * Loads and indexes the Compose bases catalog from JSON manifest files. * @@ -16,6 +14,12 @@ export { resolveCatalogSelection, getAccessBases, getAvailableLibraryFacets, val * standard order, and stores the result on the context. */ export const ConfigModule = { + EMPTY_BASE, + getDiamondCompilerVersion, + resolveCatalogSelection, + getAccessBases, + getAvailableLibraryFacets, + validateGroupedAccessFlags, /** * Reads JSON manifest files from `bases/` and builds the {@link BasesCatalog}. * diff --git a/cli/src/modules/deployGeneration/model.ts b/cli/src/modules/deployGeneration/model.ts index 5eb34e88..98237048 100644 --- a/cli/src/modules/deployGeneration/model.ts +++ b/cli/src/modules/deployGeneration/model.ts @@ -1,6 +1,6 @@ import path from "node:path"; import { ComposeContext, ModuleState } from "../../context/types"; -import { getSelectedFacets } from "../scaffolding/module"; +import { ScaffoldingModule } from "../scaffolding/module"; import { ScaffoldMapEntry, SelectedFacet, SelectedFacetSource } from "../scaffolding/types"; import { DeployFacetEntry, DeployFacetGroup, DeployGenerationModel } from "./types"; import { toPosixPath } from "../../utils/files"; @@ -60,7 +60,7 @@ export function resolveDeployGenerationModel( const scaffoldEntries = getScaffoldEntries(ctx); const scaffoldByFacetName = new Map(scaffoldEntries.map((entry) => [entry.facetName, entry])); - const selectedFacets = getSelectedFacets(ctx); + const selectedFacets = ScaffoldingModule.getSelectedFacets(ctx); const deployEntries = selectedFacets.map((facet: SelectedFacet): DeployFacetEntry => { const scaffoldEntry = scaffoldByFacetName.get(facet.name); diff --git a/cli/src/modules/diamondGeneration/model.ts b/cli/src/modules/diamondGeneration/model.ts index bb2a940b..c47a7304 100644 --- a/cli/src/modules/diamondGeneration/model.ts +++ b/cli/src/modules/diamondGeneration/model.ts @@ -1,9 +1,9 @@ import path from "node:path"; import { ComposeContext } from "../../context/types"; import { ConstructorEntry, Erc165Entry } from "../config/types"; -import { getSelectedFacets, targetDirectoryForFacet } from "../scaffolding/module"; +import { ScaffoldingModule } from "../scaffolding/module"; import { BasesCatalog } from "../config/types"; -import { resolveCatalogSelection, EMPTY_BASE } from "../config/module"; +import { ConfigModule } from "../config/module"; import { DiamondGenerationFile, DiamondGenerationModel, DiamondImport } from "./types"; import { contractNameFromSourcePath, @@ -32,7 +32,7 @@ export function resolveDiamondGenerationModel( const catalog = ctx.config.bases as BasesCatalog; const selectedBaseKey = String(ctx.param.base ?? ""); const selectedBase = selectedBaseKey === "none" - ? EMPTY_BASE + ? ConfigModule.EMPTY_BASE : catalog.features[selectedBaseKey]; const projectRoot = String(ctx.param.projectRoot ?? ""); const solidityPragma = catalog.globals.diamond?.pragma; @@ -51,8 +51,8 @@ export function resolveDiamondGenerationModel( throw new Error("Cannot generate Diamond.sol: diamond pragma is missing or invalid."); } - const selectedFacets = getSelectedFacets(ctx); - const selection = resolveCatalogSelection( + const selectedFacets = ScaffoldingModule.getSelectedFacets(ctx); + const selection = ConfigModule.resolveCatalogSelection( catalog, selectedBaseKey, (ctx.param.libraries as string[] | undefined) ?? [], @@ -99,7 +99,7 @@ export function resolveDiamondGenerationModel( if (entry.mod) { const alias = contractNameFromSourcePath(entry.mod); - const target = path.join(targetDirectoryForFacet(contractSourceRoot, facet), path.basename(entry.mod)); + const target = path.join(ScaffoldingModule.targetDirectoryForFacet(contractSourceRoot, facet), path.basename(entry.mod)); if (!isComposePackagePath(entry.mod)) { addGenerationFile(files, resolveCatalogSourceForRead(entry.mod), target); } diff --git a/cli/src/modules/info/scanner.ts b/cli/src/modules/info/scanner.ts index 6dd0d3bd..1688359a 100644 --- a/cli/src/modules/info/scanner.ts +++ b/cli/src/modules/info/scanner.ts @@ -6,7 +6,7 @@ import { parseExportedSelectorSignatures, parseSolidityFunctions, } from "../../utils/solidityText"; -import { parseStorageLayouts } from "../scaffolding/module"; +import { ScaffoldingModule } from "../scaffolding/module"; import { ComposeProjectInfo, DiamondInfo, FacetInfo } from "./types"; /** @@ -188,7 +188,7 @@ function extractFacetInfo( } // Extract storage layouts - const storageScan = parseStorageLayouts(source); + const storageScan = ScaffoldingModule.parseStorageLayouts(source); facet.storageSlots = storageScan.layouts.map((layout) => ({ slot: layout.slot, layout: layout.layout, diff --git a/cli/src/modules/init/module.ts b/cli/src/modules/init/module.ts index 7f95e8ab..c30bd97e 100644 --- a/cli/src/modules/init/module.ts +++ b/cli/src/modules/init/module.ts @@ -1,12 +1,6 @@ import { ComposeContext } from "../../context/types"; import { BasesCatalog } from "../config/types"; -import { - EMPTY_BASE, - getAccessBases, - getAvailableLibraryFacets, - resolveCatalogSelection, - validateGroupedAccessFlags, -} from "../config/module"; +import { ConfigModule } from "../config/module"; import { checkboxTheme, getOwnershipChoices, @@ -21,7 +15,7 @@ import { getFrameworkDependencies } from "./frameworkDeps"; import { resolveAccessFlags } from "./flags"; import { splitCommaSeparated } from "../../utils/strings"; import { validateProjectName, validateProjectNameWithFolder } from "./projectNameValidation"; -import { TerminalOutputModule } from "../terminalOutput/module"; +import { showComposeHeader, showDependencies, showSuccess } from "./output"; /** * Handles interactive and non-interactive init input collection. @@ -31,6 +25,8 @@ import { TerminalOutputModule } from "../terminalOutput/module"; * the assembled configuration on the context. */ export const InitModule = { + showComposeHeader, + showSuccess, /** * Runs the init flow non-interactively from CLI flags. * @@ -74,7 +70,7 @@ export const InitModule = { selectedAccessExtensions, } = resolveAccessFlags(ctx.param); - validateGroupedAccessFlags( + ConfigModule.validateGroupedAccessFlags( catalog, baseKey, selectedOwnership, @@ -83,7 +79,7 @@ export const InitModule = { selectedRoleAccessExtensions, ); - const selection = resolveCatalogSelection( + const selection = ConfigModule.resolveCatalogSelection( catalog, baseKey, selectedLibraries, @@ -196,7 +192,7 @@ export const InitModule = { }); const selectedBase = selectedBaseKey === "none" - ? EMPTY_BASE + ? ConfigModule.EMPTY_BASE : catalog.features[selectedBaseKey]; const availableExtensions = selectedBase.optional ?? {}; @@ -210,7 +206,7 @@ export const InitModule = { }) : []; - const availableLibraryFacets = getAvailableLibraryFacets(catalog, selectedBase); + const availableLibraryFacets = ConfigModule.getAvailableLibraryFacets(catalog, selectedBase); const libraryChoices = toFacetChoices(Object.keys(availableLibraryFacets)); const selectedLibraries = await checkbox({ @@ -219,7 +215,7 @@ export const InitModule = { theme: checkboxTheme, }); - const accessBases = getAccessBases(catalog, selectedBaseKey); + const accessBases = ConfigModule.getAccessBases(catalog, selectedBaseKey); const selectedOwnership = selectedBase.accessType === "ownership" ? undefined : await select({ @@ -265,14 +261,14 @@ export const InitModule = { ]; const { deps, packageType } = getFrameworkDependencies(framework, String(ctx.param.toolbox)); - TerminalOutputModule.showDependencies(deps, packageType); + showDependencies(deps, packageType); const installDeps = await (await loadPrompts()).confirm({ message: "Install project dependencies?", default: true, }); ctx.param.installDeps = installDeps; - const selection = resolveCatalogSelection( + const selection = ConfigModule.resolveCatalogSelection( catalog, selectedBaseKey, selectedLibraries, diff --git a/cli/src/modules/init/output.ts b/cli/src/modules/init/output.ts new file mode 100644 index 00000000..2257578d --- /dev/null +++ b/cli/src/modules/init/output.ts @@ -0,0 +1,74 @@ +import { ComposeContext } from "../../context/types"; +import { cyan, dim, green, yellow } from "../../utils/terminal"; +import { COMPOSE_HEADER, COMPOSE_DOCS_URL } from "../../utils/metadata"; + +/** + * Prints the Compose welcome banner and documentation URL. + */ +export function showComposeHeader(): void { + console.log(cyan(COMPOSE_HEADER)); + console.log(cyan("Scaffold your diamond smart contracts project with Compose")); + console.log(cyan(`Explore our library: ${COMPOSE_DOCS_URL}\n`)); +} + +/** + * Displays a dimmed list of dependencies that will be installed. + * + * @param deps - Array of dependency objects with name and version. + * @param packageType - Label for the package type (e.g. "npm packages", "forge packages"). + */ +export function showDependencies(deps: { name: string; version: string }[], packageType: string): void { + console.log(dim(`\nThe following ${packageType} will be installed:\n`)); + for (const dep of deps) { + console.log(dim(` ${dep.name} ${dep.version}`)); + } + console.log(""); +} + +/** + * Prints the success message with framework-specific next steps. + * + * Displays the project name, scaffolded path, and a numbered list of + * next-step commands (e.g. `forge build && forge test` for Foundry, + * `npx hardhat compile && npx hardhat test` for Hardhat). Adjusts steps + * based on whether `installDeps` is enabled. + * + * @param ctx - The compose context with `param.projectName`, `param.projectRoot`, and `param.framework`. + */ +export function showSuccess(ctx: ComposeContext): void { + const projectName = String(ctx.param.projectName ?? "my-diamond"); + const projectRoot = String(ctx.param.projectRoot ?? ""); + + console.log(green(`\n✔`) + ` Project "${projectName}" scaffolded in "${projectRoot}"\n`); + console.log(green("Next steps:")); + + let stepCount = 1; + if (projectRoot !== process.cwd()) { + console.log(green(`${stepCount}.`) + ` cd ${projectName}`); + stepCount++; + } + + const framework = String(ctx.param.framework ?? "foundry"); + if (framework === "foundry") { + const installDeps = ctx.param.installDeps !== false; + if (installDeps) { + console.log(green(`${stepCount}.`) + ` forge build && forge test`); + } else { + console.log(green(`${stepCount}.`) + ` forge install Perfect-Abstractions/Compose`); + console.log(green(`${stepCount + 1}.`) + ` forge build && forge test`); + } + } else if (framework === "hardhat") { + const installDeps = ctx.param.installDeps !== false; + if (installDeps) { + console.log(green(`${stepCount}.`) + ` npx hardhat compile && npx hardhat test`); + } else { + console.log(green(`${stepCount}.`) + ` npm install`); + console.log(green(`${stepCount + 1}.`) + ` npx hardhat compile && npx hardhat test`); + } + } + + console.log(""); + console.log(green("You're all set. We hope you'll Compose something great!\n")); + console.log(yellow(`If this helped you, please give us a star on GitHub\n`) + `✨ https://github.com/Perfect-Abstractions/Compose ✨\n`); + console.log(`Please report any issues or feedback:\nhttps://github.com/Perfect-Abstractions/Compose/issues\n`); +} diff --git a/cli/src/modules/scaffolding/facetSelection.ts b/cli/src/modules/scaffolding/facetSelection.ts index 36bfbf0e..5235c70d 100644 --- a/cli/src/modules/scaffolding/facetSelection.ts +++ b/cli/src/modules/scaffolding/facetSelection.ts @@ -1,5 +1,5 @@ import { BasesCatalog, FacetEntry } from "../config/types"; -import { resolveCatalogSelection } from "../config/module"; +import { ConfigModule } from "../config/module"; import { SelectedFacet } from "./types"; import { ComposeContext } from "../../context/types"; import { isDeepEqual } from "../../utils/objects"; @@ -22,7 +22,7 @@ export function getSelectedFacets(ctx: ComposeContext): SelectedFacet[] { const selectedExtensionNames = new Set((ctx.param.extensions as string[] | undefined) ?? []); const selectedAccessNames = new Set((ctx.param.access as string[] | undefined) ?? []); const selectedAccessExtensionNames = new Set((ctx.param.accessExtensions as string[] | undefined) ?? []); - const selection = resolveCatalogSelection( + const selection = ConfigModule.resolveCatalogSelection( catalog, selectedBaseKey, [...selectedLibraryNames], diff --git a/cli/src/modules/scaffolding/module.ts b/cli/src/modules/scaffolding/module.ts index ac8749ba..7f26b231 100644 --- a/cli/src/modules/scaffolding/module.ts +++ b/cli/src/modules/scaffolding/module.ts @@ -11,10 +11,6 @@ import { getSelectedFacets } from "./facetSelection"; import { parseStorageLayouts } from "./storage"; import { targetDirectoryForFacet } from "./paths"; -export { getSelectedFacets } from "./facetSelection"; -export { targetDirectoryForFacet } from "./paths"; -export { parseStorageLayouts } from "./storage"; - /** * Scans selected Solidity facets and writes the final project configuration. * @@ -23,6 +19,9 @@ export { parseStorageLayouts } from "./storage"; * `compose.json` to the project root. */ export const ScaffoldingModule = { + getSelectedFacets, + targetDirectoryForFacet, + parseStorageLayouts, /** * Records the framework scaffold map so later modules can resolve generated files. * diff --git a/cli/src/modules/terminalOutput/module.ts b/cli/src/modules/terminalOutput/module.ts deleted file mode 100644 index f3eb487a..00000000 --- a/cli/src/modules/terminalOutput/module.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { ComposeContext } from "../../context/types"; -import { BasesCatalog, BaseDefinition } from "../config/types"; -import { cyan, dim, green, red, yellow } from "../../utils/terminal"; -import { COMPOSE_HEADER, COMPOSE_DOCS_URL } from "../../utils/metadata"; -import { - getFacetScanState, - getSelectorExportValidationState, - getSelectorCollisionValidationState, - getIdentifierCollisionValidationState, -} from "../validation/module"; -import { FacetScanWarning } from "../validation/types"; - -/** - * Terminal UI module for CLI output formatting. - * - * Provides methods for rendering the welcome header, help text, validation - * reports, success messages, and validation output. All output is colorized - * using the terminal utility helpers. - */ -export const TerminalOutputModule = { - /** - * Prints the Compose welcome banner and documentation URL. - */ - showComposeHeader() { - console.log(cyan(COMPOSE_HEADER)); - console.log(cyan("Scaffold your diamond smart contracts project with Compose")); - console.log(cyan(`Explore our library: ${COMPOSE_DOCS_URL}\n`)); - }, - - /** - * Displays a dimmed list of dependencies that will be installed. - * - * @param deps - Array of dependency objects with name and version. - * @param packageType - Label for the package type (e.g. "npm packages", "forge packages"). - */ - showDependencies(deps: { name: string; version: string }[], packageType: string): void { - console.log(dim(`\nThe following ${packageType} will be installed:\n`)); - for (const dep of deps) { - console.log(dim(` ${dep.name} ${dep.version}`)); - } - console.log(""); - }, - - - - /** - * Renders validation warnings and fail-fast error reports. - * - * Displays facet scan warnings (yellow), then checks for selector export - * issues, selector collisions, and identifier collisions in order. Each - * failure is printed in red with details and the method returns early. - * - * @param ctx - The compose context with validation state populated. - * @returns The context unchanged. - */ - async showReport(ctx: ComposeContext): Promise { - const facetScan = getFacetScanState(ctx); - const scanWarnings = (facetScan?.result?.facets ?? []) - .map((facet: FacetScanWarning) => facet) - .filter((facet: FacetScanWarning) => facet.warnings.length > 0); - - if (scanWarnings.length > 0) { - console.warn(yellow("\nValidation warnings")); - for (const facet of scanWarnings) { - console.warn(`\n${facet.facetName}`); - console.warn(` ${facet.path}`); - for (const warning of facet.warnings) { - console.warn(` ${warning}`); - } - } - } - - const selectorExportValidation = getSelectorExportValidationState(ctx); - - if (selectorExportValidation && !selectorExportValidation.success) { - console.error(red("\nValidation failed")); - console.error(red(selectorExportValidation.error?.message ?? "Validation failed.")); - - for (const issue of selectorExportValidation.result?.issues ?? []) { - console.error(`\n${issue.facetName}`); - console.error(` ${issue.path}`); - - if (issue.missingExports.length > 0) { - console.error(` Missing exports: ${issue.missingExports.join(", ")}`); - } - - if (issue.extraExports.length > 0) { - console.error(` Extra exports: ${issue.extraExports.join(", ")}`); - } - } - - return ctx; - } - - const selectorCollisionValidation = getSelectorCollisionValidationState(ctx); - - if (selectorCollisionValidation && !selectorCollisionValidation.success) { - console.error(red("\nValidation failed")); - console.error(red(selectorCollisionValidation.error?.message ?? "Validation failed.")); - - for (const collision of selectorCollisionValidation.result?.collisions ?? []) { - console.error(`\n${collision.selector}`); - for (const owner of collision.owners) { - console.error(` ${owner.facetName}: ${owner.signature}`); - console.error(` ${owner.path}`); - } - } - - return ctx; - } - - const identifierCollisionValidation = getIdentifierCollisionValidationState(ctx); - - if (identifierCollisionValidation && !identifierCollisionValidation.success) { - console.error(red("\nValidation failed")); - console.error(red(identifierCollisionValidation.error?.message ?? "Validation failed.")); - - for (const collision of identifierCollisionValidation.result?.collisions ?? []) { - console.error(`\n${collision.identifier}`); - for (const owner of collision.owners) { - console.error(` ${owner.facetName}: [${owner.layout.join(", ")}]`); - console.error(` ${owner.path}`); - } - } - } - - return ctx; - }, - - /** - * Prints the success message with framework-specific next steps. - * - * Displays the project name, scaffolded path, and a numbered list of - * next-step commands (e.g. `forge build && forge test` for Foundry, - * `npx hardhat compile && npx hardhat test` for Hardhat). Adjusts steps - * based on whether `installDeps` is enabled. - * - * @param ctx - The compose context with `param.projectName`, `param.projectRoot`, and `param.framework`. - */ - showSuccess(ctx: ComposeContext): void { - const projectName = String(ctx.param.projectName ?? "my-diamond"); - const projectRoot = String(ctx.param.projectRoot ?? ""); - - console.log(green(`\n✔`) + ` Project "${projectName}" scaffolded in "${projectRoot}"\n`); - console.log(green("Next steps:")); - - let stepCount = 1; - if (projectRoot !== process.cwd()) { - console.log(green(`${stepCount}.`) + ` cd ${projectName}`); - stepCount++; - } - - const framework = String(ctx.param.framework ?? "foundry"); - if (framework === "foundry") { - const installDeps = ctx.param.installDeps !== false; - if (installDeps) { - console.log(green(`${stepCount}.`) + ` forge build && forge test`); - } else { - console.log(green(`${stepCount}.`) + ` forge install Perfect-Abstractions/Compose`); - console.log(green(`${stepCount + 1}.`) + ` forge build && forge test`); - } - } else if (framework === "hardhat") { - const installDeps = ctx.param.installDeps !== false; - if (installDeps) { - console.log(green(`${stepCount}.`) + ` npx hardhat compile && npx hardhat test`); - } else { - console.log(green(`${stepCount}.`) + ` npm install`); - console.log(green(`${stepCount + 1}.`) + ` npx hardhat compile && npx hardhat test`); - } - } - - console.log(""); - console.log(green("You're all set. We hope you'll Compose something great!\n")); - console.log(yellow(`If this helped you, please give us a star on GitHub\n`) + `✨ https://github.com/Perfect-Abstractions/Compose ✨\n`); - console.log(`Please report any issues or feedback:\nhttps://github.com/Perfect-Abstractions/Compose/issues\n`); - }, - - /** - * Displays available Compose bases grouped by type with facet counts. - * - * Reads the bases catalog from `ctx.config.bases` and prints each base - * grouped into Features and Access Control sections. - * - * @param ctx - The compose context with the loaded bases catalog. - */ - showTemplates(ctx: ComposeContext): void { - const catalog = ctx.config.bases as BasesCatalog; - const features = catalog.features; - - const featureBases: [string, BaseDefinition][] = []; - const accessBases: [string, BaseDefinition][] = []; - - for (const [key, definition] of Object.entries(features)) { - if (definition.access) { - accessBases.push([key, definition]); - } else { - featureBases.push([key, definition]); - } - } - - const maxIdLen = Math.max( - ...featureBases.map(([k]) => k.length), - ...accessBases.map(([k]) => k.length), - ); - - console.log(`\n${cyan("Compose Catalog")}\n`); - - if (featureBases.length > 0) { - console.log(dim(" Features")); - console.log(dim(" " + "─".repeat(maxIdLen + 28))); - for (const [key, definition] of featureBases) { - const required = Object.keys(definition.required).length; - const optional = Object.keys(definition.optional).length; - const id = key.padEnd(maxIdLen + 2); - const label = dim(definition.label.padEnd(22)); - const counts = `${green(`${required} required`)}, ${yellow(`${optional} optional`)}`; - console.log(` ${cyan(id)}${label}${counts}`); - } - console.log(""); - } - - if (accessBases.length > 0) { - console.log(dim(" Access Control")); - console.log(dim(" " + "─".repeat(maxIdLen + 28))); - for (const [key, definition] of accessBases) { - const required = Object.keys(definition.required).length; - const optional = Object.keys(definition.optional).length; - const id = key.padEnd(maxIdLen + 2); - const label = dim(definition.label.padEnd(22)); - const counts = `${green(`${required} required`)}, ${yellow(`${optional} optional`)}`; - console.log(` ${cyan(id)}${label}${counts}`); - } - console.log(""); - } - - console.log(dim(" Use --base with compose init\n")); - }, -}; \ No newline at end of file diff --git a/cli/src/modules/validation/module.ts b/cli/src/modules/validation/module.ts index b8564d66..6e9f9cff 100644 --- a/cli/src/modules/validation/module.ts +++ b/cli/src/modules/validation/module.ts @@ -7,12 +7,12 @@ import { } from "./validators"; import { getFacetScanResult, + getFacetScanState, getIdentifierCollisionValidationState, getSelectorCollisionValidationState, getSelectorExportValidationState, } from "./state"; - -export { getFacetScanState, getSelectorExportValidationState, getSelectorCollisionValidationState, getIdentifierCollisionValidationState } from "./state"; +import { showReport } from "./output"; /** * Validates facet scans for selector export correctness and collision-free layouts. @@ -26,6 +26,12 @@ export { getFacetScanState, getSelectorExportValidationState, getSelectorCollisi * `success: false` when issues are found. */ export const ValidationModule = { + showReport, + getFacetScanState, + getSelectorExportValidationState, + getSelectorCollisionValidationState, + getIdentifierCollisionValidationState, + /** * Returns true when selector export validation has found blocking issues. * diff --git a/cli/src/modules/validation/output.ts b/cli/src/modules/validation/output.ts new file mode 100644 index 00000000..ce04660e --- /dev/null +++ b/cli/src/modules/validation/output.ts @@ -0,0 +1,93 @@ +import { ComposeContext } from "../../context/types"; +import { yellow, red } from "../../utils/terminal"; +import { + getFacetScanState, + getSelectorExportValidationState, + getSelectorCollisionValidationState, + getIdentifierCollisionValidationState, +} from "./state"; +import { FacetScanWarning } from "./types"; + +/** + * Renders validation warnings and fail-fast error reports. + * + * Displays facet scan warnings (yellow), then checks for selector export + * issues, selector collisions, and identifier collisions in order. Each + * failure is printed in red with details and the method returns early. + * + * @param ctx - The compose context with validation state populated. + * @returns The context unchanged. + */ +export async function showReport(ctx: ComposeContext): Promise { + const facetScan = getFacetScanState(ctx); + const scanWarnings = (facetScan?.result?.facets ?? []) + .map((facet: FacetScanWarning) => facet) + .filter((facet: FacetScanWarning) => facet.warnings.length > 0); + + if (scanWarnings.length > 0) { + console.warn(yellow("\nValidation warnings")); + for (const facet of scanWarnings) { + console.warn(`\n${facet.facetName}`); + console.warn(` ${facet.path}`); + for (const warning of facet.warnings) { + console.warn(` ${warning}`); + } + } + } + + const selectorExportValidation = getSelectorExportValidationState(ctx); + + if (selectorExportValidation && !selectorExportValidation.success) { + console.error(red("\nValidation failed")); + console.error(red(selectorExportValidation.error?.message ?? "Validation failed.")); + + for (const issue of selectorExportValidation.result?.issues ?? []) { + console.error(`\n${issue.facetName}`); + console.error(` ${issue.path}`); + + if (issue.missingExports.length > 0) { + console.error(` Missing exports: ${issue.missingExports.join(", ")}`); + } + + if (issue.extraExports.length > 0) { + console.error(` Extra exports: ${issue.extraExports.join(", ")}`); + } + } + + return ctx; + } + + const selectorCollisionValidation = getSelectorCollisionValidationState(ctx); + + if (selectorCollisionValidation && !selectorCollisionValidation.success) { + console.error(red("\nValidation failed")); + console.error(red(selectorCollisionValidation.error?.message ?? "Validation failed.")); + + for (const collision of selectorCollisionValidation.result?.collisions ?? []) { + console.error(`\n${collision.selector}`); + for (const owner of collision.owners) { + console.error(` ${owner.facetName}: ${owner.signature}`); + console.error(` ${owner.path}`); + } + } + + return ctx; + } + + const identifierCollisionValidation = getIdentifierCollisionValidationState(ctx); + + if (identifierCollisionValidation && !identifierCollisionValidation.success) { + console.error(red("\nValidation failed")); + console.error(red(identifierCollisionValidation.error?.message ?? "Validation failed.")); + + for (const collision of identifierCollisionValidation.result?.collisions ?? []) { + console.error(`\n${collision.identifier}`); + for (const owner of collision.owners) { + console.error(` ${owner.facetName}: [${owner.layout.join(", ")}]`); + console.error(` ${owner.path}`); + } + } + } + + return ctx; +} diff --git a/cli/src/pipelines/catalogPipeline.ts b/cli/src/pipelines/catalogPipeline.ts index d1acec77..7d03d5a2 100644 --- a/cli/src/pipelines/catalogPipeline.ts +++ b/cli/src/pipelines/catalogPipeline.ts @@ -1,6 +1,6 @@ import { ComposeContext } from "../context/types"; import { ConfigModule } from "../modules/config/module"; -import { TerminalOutputModule } from "../modules/terminalOutput/module"; +import { CatalogModule } from "../modules/catalog/module"; /** * Catalog Pipeline. @@ -11,7 +11,7 @@ import { TerminalOutputModule } from "../modules/terminalOutput/module"; export const CatalogPipeline = { async execute(ctx: ComposeContext): Promise { ctx = await ConfigModule.loadBasesCatalog(ctx); - TerminalOutputModule.showTemplates(ctx); + CatalogModule.showTemplates(ctx); return ctx; }, }; diff --git a/cli/src/pipelines/initPipeline.ts b/cli/src/pipelines/initPipeline.ts index dc0776a6..0d563232 100644 --- a/cli/src/pipelines/initPipeline.ts +++ b/cli/src/pipelines/initPipeline.ts @@ -1,18 +1,16 @@ import { ComposeContext } from "../context/types"; import { ConfigModule } from "../modules/config/module"; -import { TerminalOutputModule } from "../modules/terminalOutput/module"; import { InitModule } from "../modules/init/module"; +import { ValidationModule } from "../modules/validation/module"; import { PreflightModule } from "../modules/preflight/module"; import { ProjectDirModule } from "../modules/projectDir/module"; import { ScaffoldingModule } from "../modules/scaffolding/module"; import { DiamondGenerationModule } from "../modules/diamondGeneration/module"; import { DeployGenerationModule } from "../modules/deployGeneration/module"; import { TestGenerationModule } from "../modules/testGeneration/module"; -import { ValidationModule } from "../modules/validation/module"; import { DependencyKey } from "../resolver/dependencyKey"; import { DependencyResolver } from "../resolver/dependencyResolver"; import { IFrameworkAdapter } from "../adapters/interface/IFrameworkAdapter"; -import { getDiamondCompilerVersion } from "../modules/config/module"; import { BasesCatalog } from "../modules/config/types"; /** @@ -30,7 +28,7 @@ export const InitPipeline = { * @returns Context with init results or validation errors */ async execute(ctx: ComposeContext): Promise { - TerminalOutputModule.showComposeHeader(); + InitModule.showComposeHeader(); ctx = await ConfigModule.loadBasesCatalog(ctx); @@ -61,7 +59,7 @@ export const InitPipeline = { const root = String(ctx.param.projectRoot ?? ""); const contractSourceRoot = adapter.getContractSourceRoot(root); - const compilerVersion = getDiamondCompilerVersion(ctx.config.bases as BasesCatalog); + const compilerVersion = ConfigModule.getDiamondCompilerVersion(ctx.config.bases as BasesCatalog); const projectName = String(ctx.param.projectName ?? "my-diamond"); const installDeps = ctx.param.installDeps !== false; @@ -74,7 +72,7 @@ export const InitPipeline = { ctx = await ValidationModule.validateSelectorExports(ctx); if (ValidationModule.hasSelectorExportFailure(ctx)) { - ctx = await TerminalOutputModule.showReport(ctx); + ctx = await ValidationModule.showReport(ctx); return ctx; } @@ -83,14 +81,14 @@ export const InitPipeline = { }); if (ValidationModule.hasSelectorCollisionFailure(ctx)) { - ctx = await TerminalOutputModule.showReport(ctx); + ctx = await ValidationModule.showReport(ctx); return ctx; } ctx = await ValidationModule.detectIdentifierCollisions(ctx); if (ValidationModule.hasIdentifierCollisionFailure(ctx)) { - ctx = await TerminalOutputModule.showReport(ctx); + ctx = await ValidationModule.showReport(ctx); return ctx; } @@ -116,14 +114,14 @@ export const InitPipeline = { error: null, }; - ctx = await TerminalOutputModule.showReport(ctx); + ctx = await ValidationModule.showReport(ctx); if (ValidationModule.hasBlockingFailure(ctx)) { return ctx; } if (ctx.state.initPipeline?.success) { - TerminalOutputModule.showSuccess(ctx); + InitModule.showSuccess(ctx); } return ctx;