diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 559add55dbd6..000000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,538 +0,0 @@ -version: 2 - -aliases: - - &docker - - image: circleci/openjdk:8-jdk-node-browsers - - - &environment - TZ: /usr/share/zoneinfo/America/Los_Angeles - - - &restore_node_modules - restore_cache: - name: Restore node_modules cache - keys: - - v2-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-modules - - - &TEST_PARALLELISM 20 - - - &attach_workspace - at: build - - - &process_artifacts - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: node ./scripts/rollup/consolidateBundleSizes.js - - run: ./scripts/circleci/pack_and_store_artifact.sh - - store_artifacts: - path: ./node_modules.tgz - - store_artifacts: - path: ./build.tgz - - store_artifacts: - path: ./build/bundle-sizes.json - - store_artifacts: - # TODO: Update release script to use local file instead of pulling - # from artifacts. - path: ./scripts/error-codes/codes.json - - persist_to_workspace: - root: build - paths: - - bundle-sizes.json - -jobs: - setup: - docker: *docker - environment: *environment - - steps: - - checkout - - run: - name: Nodejs Version - command: node --version - - restore_cache: - name: Restore yarn cache - key: v2-node-{{ arch }}-{{ checksum "yarn.lock" }}-yarn - - run: - name: Install Packages - command: yarn --frozen-lockfile --cache-folder ~/.cache/yarn - - save_cache: - # Store the yarn cache globally for all lock files with this same - # checksum. This will speed up the setup job for all PRs where the - # lockfile is the same. - name: Save yarn cache for future installs - key: v2-node-{{ arch }}-{{ checksum "yarn.lock" }}-yarn - paths: - - ~/.cache/yarn - - save_cache: - # Store node_modules for all jobs in this workflow so that they don't - # need to each run a yarn install for each job. This will speed up - # all jobs run on this branch with the same lockfile. - name: Save node_modules cache - # This cache key is per branch, a yarn install in setup is required. - key: v2-node-{{ arch }}-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-modules - paths: - - node_modules - - yarn_lint: - docker: *docker - environment: *environment - - steps: - - checkout - - *restore_node_modules - - run: node ./scripts/prettier/index - - run: node ./scripts/tasks/eslint - - run: ./scripts/circleci/check_license.sh - - run: ./scripts/circleci/check_modules.sh - - run: ./scripts/circleci/test_print_warnings.sh - - yarn_flow: - docker: *docker - environment: *environment - - steps: - - checkout - - *restore_node_modules - - run: node ./scripts/tasks/flow-ci - - RELEASE_CHANNEL_stable_yarn_test: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=stable --ci - - yarn_test: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --ci - - RELEASE_CHANNEL_stable_yarn_test_www: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-classic --ci - - RELEASE_CHANNEL_stable_yarn_test_www_variant: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-classic --variant --ci - - RELEASE_CHANNEL_stable_yarn_test_prod_www: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-classic --prod --ci - - RELEASE_CHANNEL_stable_yarn_test_prod_www_variant: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-classic --prod --variant --ci - - yarn_test_www: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-modern --ci - - yarn_test_www_variant: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-modern --variant --ci - - yarn_test_prod_www: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-modern --prod --ci - - yarn_test_prod_www_variant: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=www-modern --prod --variant --ci - - RELEASE_CHANNEL_stable_yarn_test_persistent: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=stable --persistent --ci - - RELEASE_CHANNEL_stable_yarn_test_prod: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=stable --prod --ci - - yarn_test_prod: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: yarn test --release-channel=experimental --prod --ci - - RELEASE_CHANNEL_stable_yarn_build: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - *restore_node_modules - - run: - environment: - RELEASE_CHANNEL: stable - command: | - ./scripts/circleci/add_build_info_json.sh - ./scripts/circleci/update_package_versions.sh - yarn build - - run: echo "stable" >> build/RELEASE_CHANNEL - - persist_to_workspace: - root: build - paths: - - RELEASE_CHANNEL - - facebook-www - - facebook-react-native - - node_modules - - react-native - - dist - - sizes/*.json - - yarn_build: - docker: *docker - environment: *environment - parallelism: 20 - steps: - - checkout - - *restore_node_modules - - run: - environment: - RELEASE_CHANNEL: experimental - command: | - ./scripts/circleci/add_build_info_json.sh - ./scripts/circleci/update_package_versions.sh - yarn build - - run: echo "experimental" >> build/RELEASE_CHANNEL - - persist_to_workspace: - root: build - paths: - - RELEASE_CHANNEL - - facebook-www - - facebook-react-native - - node_modules - - react-native - - dist - - sizes/*.json - - build_devtools_and_process_artifacts: - docker: *docker - environment: *environment - parallelism: 20 - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: - environment: - RELEASE_CHANNEL: experimental - command: ./scripts/circleci/pack_and_store_devtools_artifacts.sh - - store_artifacts: - path: ./build/devtools.tgz - - # These jobs are named differently so we can distinguish the stable and - # and experimental artifacts - process_artifacts: *process_artifacts - process_artifacts_experimental: *process_artifacts - - sizebot_stable: - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - # This runs in the process_artifacts job, too, but it's faster to run - # this step in both jobs instead of running the jobs sequentially - - run: node ./scripts/rollup/consolidateBundleSizes.js - - run: - environment: - RELEASE_CHANNEL: stable - command: node ./scripts/tasks/danger - - sizebot_experimental: - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - # This runs in the process_artifacts job, too, but it's faster to run - # this step in both jobs instead of running the jobs sequentially - - run: node ./scripts/rollup/consolidateBundleSizes.js - - run: - environment: - RELEASE_CHANNEL: experimental - command: node ./scripts/tasks/danger - - yarn_lint_build: - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: yarn lint-build - - run: scripts/circleci/check_minified_errors.sh - - RELEASE_CHANNEL_stable_yarn_lint_build: - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: - environment: - RELEASE_CHANNEL: stable - command: yarn lint-build - - run: scripts/circleci/check_minified_errors.sh - - RELEASE_CHANNEL_stable_yarn_test_build: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: yarn test --release-channel=stable --build --ci - - yarn_test_build: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: yarn test --release-channel=experimental --build --ci - - yarn_test_build_devtools: - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: yarn test --project=devtools --build --ci - - RELEASE_CHANNEL_stable_yarn_test_dom_fixtures: - docker: *docker - environment: *environment - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: - name: Run DOM fixture tests - environment: - RELEASE_CHANNEL: stable - command: | - cd fixtures/dom - yarn --frozen-lockfile - yarn prestart - yarn test --maxWorkers=2 - - test_fuzz: - docker: *docker - environment: *environment - steps: - - checkout - - *restore_node_modules - - run: - name: Run fuzz tests - command: | - FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci - FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci - - RELEASE_CHANNEL_stable_yarn_test_build_prod: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: yarn test --release-channel=stable --build --prod --ci - - yarn_test_build_prod: - docker: *docker - environment: *environment - parallelism: *TEST_PARALLELISM - steps: - - checkout - - attach_workspace: *attach_workspace - - *restore_node_modules - - run: yarn test --release-channel=experimental --build --prod --ci - -workflows: - version: 2 - stable: - jobs: - - setup - - yarn_lint: - requires: - - setup - - yarn_flow: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test_prod: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test_persistent: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test_www: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test_www_variant: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test_prod_www: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_test_prod_www_variant: - requires: - - setup - - RELEASE_CHANNEL_stable_yarn_build: - requires: - - setup - - process_artifacts: - requires: - - RELEASE_CHANNEL_stable_yarn_build - - sizebot_stable: - requires: - - RELEASE_CHANNEL_stable_yarn_build - - RELEASE_CHANNEL_stable_yarn_lint_build: - requires: - - RELEASE_CHANNEL_stable_yarn_build - - RELEASE_CHANNEL_stable_yarn_test_build: - requires: - - RELEASE_CHANNEL_stable_yarn_build - - RELEASE_CHANNEL_stable_yarn_test_build_prod: - requires: - - RELEASE_CHANNEL_stable_yarn_build - - RELEASE_CHANNEL_stable_yarn_test_dom_fixtures: - requires: - - RELEASE_CHANNEL_stable_yarn_build - - experimental: - jobs: - - setup - - yarn_test: - requires: - - setup - - yarn_test_prod: - requires: - - setup - - yarn_test_www: - requires: - - setup - - yarn_test_www_variant: - requires: - - setup - - yarn_test_prod_www: - requires: - - setup - - yarn_test_prod_www_variant: - requires: - - setup - - yarn_build: - requires: - - setup - - process_artifacts_experimental: - requires: - - yarn_build - - sizebot_experimental: - requires: - - yarn_build - - yarn_test_build: - requires: - - yarn_build - - yarn_test_build_prod: - requires: - - yarn_build - - yarn_lint_build: - requires: - - yarn_build - - yarn_test_build_devtools: - requires: - - yarn_build - # FIXME: Temporarily disabled to unblock master. - # - build_devtools_and_process_artifacts: - # requires: - # - yarn_build - - fuzz_tests: - triggers: - - schedule: - # Fuzz tests run hourly - cron: "0 * * * *" - filters: - branches: - only: - - master - jobs: - - setup - - test_fuzz: - requires: - - setup diff --git a/.claude/instructions.md b/.claude/instructions.md new file mode 100644 index 000000000000..39573f6c4495 --- /dev/null +++ b/.claude/instructions.md @@ -0,0 +1,46 @@ +# React + +**Scope**: All code EXCEPT `/compiler/` (compiler has its own instructions). + +## Project Structure + +| Directory | Purpose | +|-----------|---------| +| `/packages/` | Publishable packages (react, react-dom, scheduler, etc.) | +| `/scripts/` | Build, test, and development scripts | +| `/fixtures/` | Test applications for manual testing | +| `/compiler/` | React Compiler (separate sub-project) | + +## Key Packages + +| Package | Purpose | +|---------|---------| +| `react` | Core React library | +| `react-dom` | DOM renderer | +| `react-reconciler` | Core reconciliation algorithm | +| `scheduler` | Cooperative scheduling | +| `react-server-dom-*` | Server Components | +| `react-devtools-*` | Developer Tools | +| `react-refresh` | Fast Refresh runtime | + +## Requirements + +- **Node**: Must be installed. Stop and prompt user if missing. +- **Package Manager**: Use `yarn` only. + +## Verification + +**IMPORTANT**: Use `/verify` to validate all changes before committing. + +## Commands + +| Command | Purpose | +|----------|----------------------| +| `/fix` | Lint and format code | +| `/test` | Run tests | +| `/flow` | Type check with Flow | +| `/flags` | Check feature flags | + +## Building + +Builds are handled by CI. Do not run locally unless instructed. diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000000..f12f21abf44b --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,44 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "if [[ \"$PWD\" != */compiler* ]]; then cat .claude/instructions.md 2>/dev/null || true; fi" + } + ] + } + ] + }, + "permissions": { + "allow": [ + "Skill(extract-errors)", + "Skill(feature-flags)", + "Skill(fix)", + "Skill(flags)", + "Skill(flow)", + "Skill(test)", + "Skill(verify)", + "Bash(yarn test:*)", + "Bash(yarn test-www:*)", + "Bash(yarn test-classic:*)", + "Bash(yarn test-stable:*)", + "Bash(yarn linc:*)", + "Bash(yarn lint:*)", + "Bash(yarn flow:*)", + "Bash(yarn prettier:*)", + "Bash(yarn build:*)", + "Bash(yarn extract-errors:*)", + "Bash(yarn flags:*)" + ], + "deny": [ + "Bash(yarn download-build:*)", + "Bash(yarn download-build-for-head:*)", + "Bash(npm:*)", + "Bash(pnpm:*)", + "Bash(bun:*)", + "Bash(npx:*)" + ] + } +} diff --git a/.claude/skills/extract-errors/SKILL.md b/.claude/skills/extract-errors/SKILL.md new file mode 100644 index 000000000000..08bb1830eb49 --- /dev/null +++ b/.claude/skills/extract-errors/SKILL.md @@ -0,0 +1,12 @@ +--- +name: extract-errors +description: Use when adding new error messages to React, or seeing "unknown error code" warnings. +--- + +# Extract Error Codes + +## Instructions + +1. Run `yarn extract-errors` +2. Report if any new errors need codes assigned +3. Check if error codes are up to date diff --git a/.claude/skills/feature-flags/SKILL.md b/.claude/skills/feature-flags/SKILL.md new file mode 100644 index 000000000000..8e3281a1af28 --- /dev/null +++ b/.claude/skills/feature-flags/SKILL.md @@ -0,0 +1,79 @@ +--- +name: feature-flags +description: Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React. +--- + +# React Feature Flags + +## Flag Files + +| File | Purpose | +|------|---------| +| `packages/shared/ReactFeatureFlags.js` | Default flags (canary), `__EXPERIMENTAL__` overrides | +| `packages/shared/forks/ReactFeatureFlags.www.js` | www channel, `__VARIANT__` overrides | +| `packages/shared/forks/ReactFeatureFlags.native-fb.js` | React Native, `__VARIANT__` overrides | +| `packages/shared/forks/ReactFeatureFlags.test-renderer.js` | Test renderer | + +## Gating Tests + +### `@gate` pragma (test-level) + +Use when the feature is completely unavailable without the flag: + +```javascript +// @gate enableViewTransition +it('supports view transitions', () => { + // This test only runs when enableViewTransition is true + // and is SKIPPED (not failed) when false +}); +``` + +### `gate()` inline (assertion-level) + +Use when the feature exists but behavior differs based on flag: + +```javascript +it('renders component', async () => { + await act(() => root.render()); + + if (gate(flags => flags.enableNewBehavior)) { + expect(container.textContent).toBe('new output'); + } else { + expect(container.textContent).toBe('legacy output'); + } +}); +``` + +## Adding a New Flag + +1. Add to `ReactFeatureFlags.js` with default value +2. Add to each fork file (`*.www.js`, `*.native-fb.js`, etc.) +3. If it should vary in www/RN, set to `__VARIANT__` in the fork file +4. Gate tests with `@gate flagName` or inline `gate()` + +## Checking Flag States + +Use `/flags` to view states across channels. See the `flags` skill for full command options. + +## `__VARIANT__` Flags (GKs) + +Flags set to `__VARIANT__` simulate gatekeepers - tested twice (true and false): + +```bash +/test www # __VARIANT__ = true +/test www variant false # __VARIANT__ = false +``` + +## Debugging Channel-Specific Failures + +1. Run `/flags --diff ` to compare values +2. Check `@gate` conditions - test may be gated to specific channels +3. Run `/test ` to isolate the failure +4. Verify flag exists in all fork files if newly added + +## Common Mistakes + +- **Forgetting both variants** - Always test `www` AND `www variant false` for `__VARIANT__` flags +- **Using @gate for behavior differences** - Use inline `gate()` if both paths should run +- **Missing fork files** - New flags must be added to ALL fork files, not just the main one +- **Wrong gate syntax** - It's `gate(flags => flags.name)`, not `gate('name')` diff --git a/.claude/skills/fix/SKILL.md b/.claude/skills/fix/SKILL.md new file mode 100644 index 000000000000..9335409af1da --- /dev/null +++ b/.claude/skills/fix/SKILL.md @@ -0,0 +1,17 @@ +--- +name: fix +description: Use when you have lint errors, formatting issues, or before committing code to ensure it passes CI. +--- + +# Fix Lint and Formatting + +## Instructions + +1. Run `yarn prettier` to fix formatting +2. Run `yarn linc` to check for remaining lint issues +3. Report any remaining manual fixes needed + +## Common Mistakes + +- **Running prettier on wrong files** - `yarn prettier` only formats changed files +- **Ignoring linc errors** - These will fail CI, fix them before committing diff --git a/.claude/skills/flags/SKILL.md b/.claude/skills/flags/SKILL.md new file mode 100644 index 000000000000..a9ddc331ea98 --- /dev/null +++ b/.claude/skills/flags/SKILL.md @@ -0,0 +1,39 @@ +--- +name: flags +description: Use when you need to check feature flag states, compare channels, or debug why a feature behaves differently across release channels. +--- + +# Feature Flags + +Arguments: +- $ARGUMENTS: Optional flags + +## Options + +| Option | Purpose | +|--------|---------| +| (none) | Show all flags across all channels | +| `--diff ` | Compare flags between channels | +| `--cleanup` | Show flags grouped by cleanup status | +| `--csv` | Output in CSV format | + +## Channels + +- `www`, `www-modern` - Meta internal +- `canary`, `next`, `experimental` - OSS channels +- `rn`, `rn-fb`, `rn-next` - React Native + +## Legend + +โœ… enabled, โŒ disabled, ๐Ÿงช `__VARIANT__`, ๐Ÿ“Š profiling-only + +## Instructions + +1. Run `yarn flags $ARGUMENTS` +2. Explain the output to the user +3. For --diff, highlight meaningful differences + +## Common Mistakes + +- **Forgetting `__VARIANT__` flags** - These are tested both ways in www; check both variants +- **Comparing wrong channels** - Use `--diff` to see exact differences diff --git a/.claude/skills/flow/SKILL.md b/.claude/skills/flow/SKILL.md new file mode 100644 index 000000000000..5ef34a201299 --- /dev/null +++ b/.claude/skills/flow/SKILL.md @@ -0,0 +1,30 @@ +--- +name: flow +description: Use when you need to run Flow type checking, or when seeing Flow type errors in React code. +--- + +# Flow Type Checking + +Arguments: +- $ARGUMENTS: Renderer to check (default: dom-node) + +## Renderers + +| Renderer | When to Use | +|----------|-------------| +| `dom-node` | Default, recommended for most changes | +| `dom-browser` | Browser-specific DOM code | +| `native` | React Native | +| `fabric` | React Native Fabric | + +## Instructions + +1. Run `yarn flow $ARGUMENTS` (use `dom-node` if no argument) +2. Report type errors with file locations +3. For comprehensive checking (slow), use `yarn flow-ci` + +## Common Mistakes + +- **Running without a renderer** - Always specify or use default `dom-node` +- **Ignoring suppressions** - Check if `$FlowFixMe` comments are masking real issues +- **Missing type imports** - Ensure types are imported from the correct package diff --git a/.claude/skills/test/SKILL.md b/.claude/skills/test/SKILL.md new file mode 100644 index 000000000000..e150ad7e549e --- /dev/null +++ b/.claude/skills/test/SKILL.md @@ -0,0 +1,46 @@ +--- +name: test +description: Use when you need to run tests for React core. Supports source, www, stable, and experimental channels. +--- + +Run tests for the React codebase. + +Arguments: +- $ARGUMENTS: Channel, flags, and test pattern + +Usage Examples: +- `/test ReactFiberHooks` - Run with source channel (default) +- `/test experimental ReactFiberHooks` - Run with experimental channel +- `/test www ReactFiberHooks` - Run with www-modern channel +- `/test www variant false ReactFiberHooks` - Test __VARIANT__=false +- `/test stable ReactFiberHooks` - Run with stable channel +- `/test classic ReactFiberHooks` - Run with www-classic channel +- `/test watch ReactFiberHooks` - Run in watch mode (TDD) + +Release Channels: +- `(default)` - Source/canary channel, uses ReactFeatureFlags.js defaults +- `experimental` - Source/experimental channel with __EXPERIMENTAL__ flags = true +- `www` - www-modern channel with __VARIANT__ flags = true +- `www variant false` - www channel with __VARIANT__ flags = false +- `stable` - What ships to npm +- `classic` - Legacy www-classic (rarely needed) + +Instructions: +1. Parse channel from arguments (default: source) +2. Map to yarn command: + - (default) โ†’ `yarn test --silent --no-watchman ` + - experimental โ†’ `yarn test -r=experimental --silent --no-watchman ` + - stable โ†’ `yarn test-stable --silent --no-watchman ` + - classic โ†’ `yarn test-classic --silent --no-watchman ` + - www โ†’ `yarn test-www --silent --no-watchman ` + - www variant false โ†’ `yarn test-www --variant=false --silent --no-watchman ` +3. Report test results and any failures + +Hard Rules: +1. **Use --silent to see failures** - This limits the test output to only failures. +2. **Use --no-watchman** - This is a common failure in sandboxing. + +Common Mistakes: +- **Running without a pattern** - Runs ALL tests, very slow. Always specify a pattern. +- **Forgetting both www variants** - Test `www` AND `www variant false` for `__VARIANT__` flags. +- **Test skipped unexpectedly** - Check for `@gate` pragma; see `feature-flags` skill. diff --git a/.claude/skills/verify/SKILL.md b/.claude/skills/verify/SKILL.md new file mode 100644 index 000000000000..daed015e28e4 --- /dev/null +++ b/.claude/skills/verify/SKILL.md @@ -0,0 +1,24 @@ +--- +name: verify +description: Use when you want to validate changes before committing, or when you need to check all React contribution requirements. +--- + +# Verification + +Run all verification steps. + +Arguments: +- $ARGUMENTS: Test pattern for the test step + +## Instructions + +Run these first in sequence: +1. Run `yarn prettier` - format code (stop if fails) +2. Run `yarn linc` - lint changed files (stop if fails) + +Then run these with subagents in parallel: +1. Use `/flow` to type check (stop if fails) +2. Use `/test` to test changes in source (stop if fails) +3. Use `/test www` to test changes in www (stop if fails) + +If all pass, show success summary. On failure, stop immediately and report the issue with suggested fixes. diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 6b3a763cf083..2164efec0c8f 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -1,10 +1,13 @@ { - "packages": ["packages/react", "packages/react-dom", "packages/scheduler"], - "buildCommand": "build --type=NODE react/index,react-dom/index,react-dom/server,react-dom/test-utils,scheduler/index,scheduler/tracing", + "packages": ["packages/react", "packages/react-dom", "packages/react-server-dom-webpack", "packages/scheduler"], + "buildCommand": "download-build-in-codesandbox-ci", + "node": "20", "publishDirectory": { - "react": "build/node_modules/react", - "react-dom": "build/node_modules/react-dom", - "scheduler": "build/node_modules/scheduler" + "react": "build/oss-experimental/react", + "react-dom": "build/oss-experimental/react-dom", + "react-server-dom-webpack": "build/oss-experimental/react-server-dom-webpack", + "scheduler": "build/oss-experimental/scheduler" }, - "sandboxes": ["new"] + "sandboxes": ["new"], + "silent": true } diff --git a/.editorconfig b/.editorconfig index 07552cfff88b..48d2b3d27e85 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,11 +8,9 @@ indent_size = 2 indent_style = space insert_final_newline = true max_line_length = 80 -trim_trailing_whitespace = true [*.md] max_line_length = 0 -trim_trailing_whitespace = false [COMMIT_EDITMSG] max_line_length = 0 diff --git a/.eslintignore b/.eslintignore index 2af8176bc3e1..956d0a182783 100644 --- a/.eslintignore +++ b/.eslintignore @@ -13,11 +13,21 @@ scripts/bench/benchmarks/**/*.js # React repository clone scripts/bench/remote-repo/ +# Compiler uses its own lint setup +compiler/ + packages/react-devtools-core/dist packages/react-devtools-extensions/chrome/build packages/react-devtools-extensions/firefox/build packages/react-devtools-extensions/shared/build +packages/react-devtools-extensions/src/ErrorTesterCompiled.js +packages/react-devtools-fusebox/dist packages/react-devtools-inline/dist +packages/react-devtools-shared/src/hooks/__tests__/__source__/__compiled__/ +packages/react-devtools-shared/src/hooks/__tests__/__source__/__untransformed__/ packages/react-devtools-shell/dist -packages/react-devtools-scheduling-profiler/dist -packages/react-devtools-scheduling-profiler/static \ No newline at end of file +packages/react-devtools-cdt-mcp/dist +packages/react-devtools-cdt-mcp/fixtures + +# Imported third-party Flow types +flow-typed/ diff --git a/.eslintrc.js b/.eslintrc.js index 6eb0eefbda3c..e197bbf95271 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -8,34 +8,221 @@ const { const restrictedGlobals = require('confusing-browser-globals'); const OFF = 0; +const WARNING = 1; const ERROR = 2; module.exports = { - extends: ['fbjs', 'prettier'], + extends: ['prettier', 'plugin:jest/recommended'], // Stop ESLint from looking for a configuration file in parent folders root: true, + reportUnusedDisableDirectives: true, + plugins: [ + 'babel', + 'ft-flow', 'jest', + 'es', 'no-for-of-loops', 'no-function-declare-after-return', 'react', 'react-internal', ], - parser: 'babel-eslint', + parser: 'hermes-eslint', parserOptions: { - ecmaVersion: 8, + ecmaVersion: 9, sourceType: 'script', - ecmaFeatures: { - experimentalObjectRestSpread: true, - }, }, // We're stricter than the default config, mostly. We'll override a few rules // and then enable some React specific ones. rules: { + 'ft-flow/array-style-complex-type': [OFF, 'verbose'], + 'ft-flow/array-style-simple-type': [OFF, 'verbose'], // TODO should be WARNING + 'ft-flow/boolean-style': ERROR, + 'ft-flow/no-dupe-keys': ERROR, + 'ft-flow/no-primitive-constructor-types': ERROR, + 'ft-flow/no-types-missing-file-annotation': OFF, // TODO should be ERROR + 'ft-flow/no-unused-expressions': ERROR, + // 'ft-flow/no-weak-types': WARNING, + // 'ft-flow/require-valid-file-annotation': ERROR, + 'es/no-optional-chaining': ERROR, + 'no-cond-assign': OFF, + 'no-constant-condition': OFF, + 'no-control-regex': OFF, + 'no-debugger': ERROR, + 'no-dupe-args': ERROR, + 'no-dupe-keys': ERROR, + 'no-duplicate-case': WARNING, + 'no-empty-character-class': WARNING, + 'no-empty': OFF, + 'no-ex-assign': WARNING, + 'no-extra-boolean-cast': WARNING, + 'no-func-assign': ERROR, + 'no-invalid-regexp': WARNING, + 'no-irregular-whitespace': WARNING, + 'no-negated-in-lhs': ERROR, + 'no-obj-calls': ERROR, + 'no-regex-spaces': WARNING, + 'no-sparse-arrays': ERROR, + 'no-unreachable': ERROR, + 'use-isnan': ERROR, + 'valid-jsdoc': OFF, + 'block-scoped-var': OFF, + complexity: OFF, + 'default-case': OFF, + 'guard-for-in': OFF, + 'no-alert': OFF, + 'no-caller': ERROR, + 'no-case-declarations': OFF, + 'no-div-regex': OFF, + 'no-else-return': OFF, + 'no-empty-pattern': WARNING, + 'no-eq-null': OFF, + 'no-eval': ERROR, + 'no-extend-native': WARNING, + 'no-extra-bind': WARNING, + 'no-fallthrough': WARNING, + 'no-implicit-coercion': OFF, + 'no-implied-eval': ERROR, + 'no-invalid-this': OFF, + 'no-iterator': OFF, + 'no-labels': [ERROR, {allowLoop: true, allowSwitch: true}], + 'no-lone-blocks': WARNING, + 'no-loop-func': OFF, + 'no-magic-numbers': OFF, + 'no-multi-str': ERROR, + 'no-native-reassign': [ERROR, {exceptions: ['Map', 'Set']}], + 'no-new-func': ERROR, + 'no-new': WARNING, + 'no-new-wrappers': WARNING, + 'no-octal-escape': WARNING, + 'no-octal': WARNING, + 'no-param-reassign': OFF, + 'no-process-env': OFF, + 'no-proto': ERROR, + 'no-redeclare': OFF, // TODO should be WARNING? + 'no-return-assign': OFF, + 'no-script-url': ERROR, + 'no-self-compare': WARNING, + 'no-sequences': WARNING, + 'no-throw-literal': ERROR, + 'no-useless-call': WARNING, + 'no-void': OFF, + 'no-warning-comments': OFF, + 'no-with': OFF, + radix: WARNING, + 'vars-on-top': OFF, + yoda: OFF, + 'init-declarations': OFF, + 'no-catch-shadow': ERROR, + 'no-delete-var': ERROR, + 'no-label-var': WARNING, + 'no-shadow-restricted-names': WARNING, + 'no-undef-init': OFF, + 'no-undef': ERROR, + 'no-undefined': OFF, + 'callback-return': OFF, + 'global-require': OFF, + 'handle-callback-err': OFF, + 'no-mixed-requires': OFF, + 'no-new-require': OFF, + 'no-path-concat': OFF, + 'no-process-exit': OFF, + 'no-restricted-modules': OFF, + 'no-sync': OFF, + camelcase: [OFF, {properties: 'always'}], + 'consistent-this': [OFF, 'self'], + 'func-names': OFF, + 'func-style': [OFF, 'declaration'], + 'id-length': OFF, + 'id-match': OFF, + 'max-depth': OFF, + 'max-nested-callbacks': OFF, + 'max-params': OFF, + 'max-statements': OFF, + 'new-cap': OFF, + 'newline-after-var': OFF, + 'no-array-constructor': ERROR, + 'no-continue': OFF, + 'no-inline-comments': OFF, + 'no-lonely-if': OFF, + 'no-negated-condition': OFF, + 'no-nested-ternary': OFF, + 'no-new-object': WARNING, + 'no-plusplus': OFF, + 'no-ternary': OFF, + 'no-underscore-dangle': OFF, + 'no-unneeded-ternary': WARNING, + 'one-var': [WARNING, {initialized: 'never'}], + 'operator-assignment': [WARNING, 'always'], + 'require-jsdoc': OFF, + 'sort-vars': OFF, + 'spaced-comment': [ + OFF, + 'always', + {exceptions: ['jshint', 'jslint', 'eslint', 'global']}, + ], + 'constructor-super': ERROR, + 'no-class-assign': WARNING, + 'no-const-assign': ERROR, + 'no-dupe-class-members': ERROR, + 'no-this-before-super': ERROR, + 'object-shorthand': OFF, + 'prefer-const': OFF, + 'prefer-spread': OFF, + 'prefer-reflect': OFF, + 'prefer-template': OFF, + 'require-yield': OFF, + 'babel/generator-star-spacing': OFF, + 'babel/new-cap': OFF, + 'babel/array-bracket-spacing': OFF, + 'babel/object-curly-spacing': OFF, + 'babel/object-shorthand': OFF, + 'babel/arrow-parens': OFF, + 'babel/no-await-in-loop': OFF, + 'babel/flow-object-type': OFF, + 'react/display-name': OFF, + 'react/forbid-prop-types': OFF, + 'react/jsx-closing-bracket-location': OFF, + 'react/jsx-curly-spacing': OFF, + 'react/jsx-equals-spacing': WARNING, + 'react/jsx-filename-extension': OFF, + 'react/jsx-first-prop-new-line': OFF, + 'react/jsx-handler-names': OFF, + 'react/jsx-indent': OFF, + 'react/jsx-indent-props': OFF, + 'react/jsx-key': OFF, + 'react/jsx-max-props-per-line': OFF, + 'react/jsx-no-bind': OFF, + 'react/jsx-no-duplicate-props': ERROR, + 'react/jsx-no-literals': OFF, + 'react/jsx-no-target-blank': OFF, + 'react/jsx-pascal-case': OFF, + 'react/jsx-sort-props': OFF, + 'react/jsx-uses-vars': ERROR, + 'react/no-comment-textnodes': OFF, + 'react/no-danger': OFF, + 'react/no-deprecated': OFF, + 'react/no-did-mount-set-state': OFF, + 'react/no-did-update-set-state': OFF, + 'react/no-direct-mutation-state': OFF, + 'react/no-multi-comp': OFF, + 'react/no-render-return-value': OFF, + 'react/no-set-state': OFF, + 'react/no-string-refs': OFF, + 'react/no-unknown-property': OFF, + 'react/prefer-es6-class': OFF, + 'react/prefer-stateless-function': OFF, + 'react/prop-types': OFF, + 'react/require-extension': OFF, + 'react/require-optimization': OFF, + 'react/require-render-return': OFF, + 'react/sort-comp': OFF, + 'react/sort-prop-types': OFF, + 'accessor-pairs': OFF, 'brace-style': [ERROR, '1tbs'], 'consistent-return': OFF, @@ -48,19 +235,28 @@ module.exports = { 'jsx-quotes': [ERROR, 'prefer-double'], 'keyword-spacing': [ERROR, {after: true, before: true}], 'no-bitwise': OFF, + 'no-console': OFF, 'no-inner-declarations': [ERROR, 'functions'], 'no-multi-spaces': ERROR, 'no-restricted-globals': [ERROR].concat(restrictedGlobals), - 'no-restricted-syntax': [ERROR, 'WithStatement'], + 'no-restricted-syntax': [ + ERROR, + 'WithStatement', + { + selector: 'MemberExpression[property.name=/^(?:substring|substr)$/]', + message: 'Prefer string.slice() over .substring() and .substr().', + }, + ], 'no-shadow': ERROR, - 'no-unused-expressions': ERROR, - 'no-unused-vars': [ERROR, {args: 'none'}], + 'no-unused-vars': [ERROR, {args: 'none', ignoreRestSiblings: true}], 'no-use-before-define': OFF, 'no-useless-concat': OFF, quotes: [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true}], 'space-before-blocks': ERROR, 'space-before-function-paren': OFF, 'valid-typeof': [ERROR, {requireStringLiterals: true}], + // Flow fails with non-string literal keys + 'no-useless-computed-key': OFF, // We apply these settings to files that should run on Node. // They can't use JSX or ES6 modules, and must be in strict mode. @@ -103,26 +299,55 @@ module.exports = { // CUSTOM RULES // the second argument of warning/invariant should be a literal string 'react-internal/no-primitive-constructors': ERROR, - 'react-internal/no-to-warn-dev-within-to-throw': ERROR, - 'react-internal/invariant-args': ERROR, - 'react-internal/warning-args': ERROR, - 'react-internal/no-production-logging': ERROR, - 'react-internal/no-cross-fork-imports': ERROR, - 'react-internal/no-cross-fork-types': [ + 'react-internal/safe-string-coercion': [ ERROR, - { - old: [ - 'firstEffect', - 'nextEffect', - // Disabled because it's also used by the Hook type. - // 'lastEffect', - ], - new: ['subtreeTag'], - }, + {isProductionUserAppCode: true}, ], + 'react-internal/warning-args': ERROR, + 'react-internal/no-production-logging': ERROR, }, overrides: [ + { + // By default, anything error message that appears the packages directory + // must have a corresponding error code. The exceptions are defined + // in the next override entry. + files: ['packages/**/*.js'], + rules: { + 'react-internal/prod-error-codes': ERROR, + }, + }, + { + // These are files where it's OK to have unminified error messages. These + // are environments where bundle size isn't a concern, like tests + // or Node. + files: [ + 'packages/react-dom/src/test-utils/**/*.js', + 'packages/react-devtools-shared/**/*.js', + 'packages/react-noop-renderer/**/*.js', + 'packages/react-refresh/**/*.js', + 'packages/react-server-dom-esm/**/*.js', + 'packages/react-server-dom-webpack/**/*.js', + 'packages/react-server-dom-turbopack/**/*.js', + 'packages/react-server-dom-parcel/**/*.js', + 'packages/react-server-dom-fb/**/*.js', + 'packages/react-flight-server-fb/**/*.js', + 'packages/react-server-dom-unbundled/**/*.js', + 'packages/react-test-renderer/**/*.js', + 'packages/react-debug-tools/**/*.js', + 'packages/react-devtools-extensions/**/*.js', + 'packages/react-devtools-facade/**/*.js', + 'packages/react-native-renderer/**/*.js', + 'packages/eslint-plugin-react-hooks/**/*.js', + 'packages/jest-react/**/*.js', + 'packages/internal-test-utils/**/*.js', + 'packages/**/__tests__/*.js', + 'packages/**/npm/*.js', + ], + rules: { + 'react-internal/prod-error-codes': OFF, + }, + }, { // We apply these settings to files that we ship through npm. // They must be ES5. @@ -141,7 +366,7 @@ module.exports = { // We apply these settings to the source files that get compiled. // They can use all features including JSX (but shouldn't use `var`). files: esNextPaths, - parser: 'babel-eslint', + parser: 'hermes-eslint', parserOptions: { ecmaVersion: 8, sourceType: 'module', @@ -156,9 +381,49 @@ module.exports = { files: ['**/__tests__/*.js'], rules: { // https://github.com/jest-community/eslint-plugin-jest - 'jest/no-focused-tests': ERROR, - 'jest/valid-expect': ERROR, - 'jest/valid-expect-in-promise': ERROR, + // Meh, who cares. + 'jest/consistent-test-it': OFF, + // Meh, we have a lot of these, who cares. + 'jest/no-alias-methods': OFF, + // We do conditions based on feature flags. + 'jest/no-conditional-expect': OFF, + // We have our own assertion helpers. + 'jest/expect-expect': OFF, + // Lame rule that fires in itRender helpers or in render methods. + 'jest/no-standalone-expect': OFF, + }, + }, + { + // Rules specific to test setup helper files. + files: [ + '**/setupTests.js', + '**/setupEnv.js', + '**/jest/TestFlags.js', + '**/dom-event-testing-library/testHelpers.js', + '**/utils/ReactDOMServerIntegrationTestUtils.js', + '**/babel/transform-react-version-pragma.js', + '**/babel/transform-test-gate-pragma.js', + ], + rules: { + // Some helpers intentionally focus tests. + 'jest/no-focused-tests': OFF, + // Test fn helpers don't use static text names. + 'jest/valid-title': OFF, + // We have our own assertion helpers. + 'jest/expect-expect': OFF, + // Some helpers intentionally disable tests. + 'jest/no-disabled-tests': OFF, + // Helpers export text function helpers. + 'jest/no-export': OFF, + // The examples in comments trigger false errors. + 'jest/no-commented-out-tests': OFF, + }, + }, + { + files: ['**/jest/TestFlags.js'], + rules: { + // The examples in comments trigger false errors. + 'jest/no-commented-out-tests': OFF, }, }, { @@ -168,44 +433,232 @@ module.exports = { 'packages/*/npm/**/*.js', 'packages/dom-event-testing-library/**/*.js', 'packages/react-devtools*/**/*.js', + 'dangerfile.js', + 'fixtures', + 'packages/react-dom/src/test-utils/*.js', ], rules: { + 'es/no-optional-chaining': OFF, 'react-internal/no-production-logging': OFF, 'react-internal/warning-args': OFF, + 'react-internal/safe-string-coercion': [ + ERROR, + {isProductionUserAppCode: false}, + ], + }, + }, + { + files: ['scripts/eslint-rules/*.js'], + plugins: ['eslint-plugin'], + rules: { + 'eslint-plugin/prefer-object-rule': ERROR, + 'eslint-plugin/require-meta-fixable': [ + ERROR, + {catchNoFixerButFixableProperty: true}, + ], + 'eslint-plugin/require-meta-has-suggestions': ERROR, }, }, { files: ['packages/react-native-renderer/**/*.js'], globals: { - nativeFabricUIManager: true, + nativeFabricUIManager: 'readonly', + RN$isNativeEventTargetEventDispatchingEnabled: 'readonly', + }, + }, + { + files: ['packages/react-server-dom-webpack/**/*.js'], + globals: { + __webpack_chunk_load__: 'readonly', + __webpack_get_script_filename__: 'readonly', + __webpack_require__: 'readonly', + }, + }, + { + files: ['packages/react-server-dom-turbopack/**/*.js'], + globals: { + __turbopack_load_by_url__: 'readonly', + __turbopack_require__: 'readonly', }, }, { - files: ['packages/react-transport-dom-webpack/**/*.js'], + files: ['packages/react-server-dom-parcel/**/*.js'], globals: { - __webpack_chunk_load__: true, - __webpack_require__: true, + parcelRequire: 'readonly', }, }, { files: ['packages/scheduler/**/*.js'], globals: { - TaskController: true, + TaskController: 'readonly', + }, + }, + { + files: [ + 'packages/react-devtools-extensions/**/*.js', + 'packages/react-devtools-shared/src/devtools/views/**/*.js', + 'packages/react-devtools-shared/src/hook.js', + 'packages/react-devtools-shared/src/backend/console.js', + 'packages/react-devtools-shared/src/backend/fiber/renderer.js', + 'packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js', + 'packages/react-devtools-shared/src/frontend/utils/withPermissionsCheck.js', + ], + globals: { + __IS_CHROME__: 'readonly', + __IS_FIREFOX__: 'readonly', + __IS_EDGE__: 'readonly', + __IS_NATIVE__: 'readonly', + __IS_INTERNAL_VERSION__: 'readonly', + chrome: 'readonly', + }, + }, + { + files: ['packages/react-devtools-shared/**/*.js'], + globals: { + __IS_INTERNAL_VERSION__: 'readonly', + }, + }, + { + files: ['packages/react-devtools-*/**/*.js'], + excludedFiles: '**/__tests__/**/*.js', + plugins: ['eslint-plugin-react-hooks-published'], + rules: { + 'react-hooks-published/rules-of-hooks': ERROR, + }, + }, + { + files: ['packages/eslint-plugin-react-hooks/src/**/*'], + extends: ['plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint', 'eslint-plugin'], + rules: { + '@typescript-eslint/no-explicit-any': OFF, + '@typescript-eslint/no-non-null-assertion': OFF, + '@typescript-eslint/array-type': [ERROR, {default: 'generic'}], + + 'es/no-optional-chaining': OFF, + + 'eslint-plugin/prefer-object-rule': ERROR, + 'eslint-plugin/require-meta-fixable': [ + ERROR, + {catchNoFixerButFixableProperty: true}, + ], + 'eslint-plugin/require-meta-has-suggestions': ERROR, }, }, ], + env: { + browser: true, + es6: true, + node: true, + jest: true, + }, + globals: { - SharedArrayBuffer: true, - - spyOnDev: true, - spyOnDevAndProd: true, - spyOnProd: true, - __PROFILE__: true, - __UMD__: true, - __EXPERIMENTAL__: true, - __VARIANT__: true, - gate: true, - trustedTypes: true, + $Flow$ModuleRef: 'readonly', + $FlowFixMe: 'readonly', + $Keys: 'readonly', + $NonMaybeType: 'readonly', + $ReadOnly: 'readonly', + $ReadOnlyArray: 'readonly', + $ArrayBufferView: 'readonly', + $Shape: 'readonly', + CallSite: 'readonly', + ConsoleTask: 'readonly', // TOOD: Figure out what the official name of this will be. + Readonly: 'readonly', + ReturnType: 'readonly', + AggregateError: 'readonly', + AnimationFrameID: 'readonly', + WeakRef: 'readonly', + // For Flow type annotation. Only `BigInt` is valid at runtime. + bigint: 'readonly', + BigInt: 'readonly', + BigInt64Array: 'readonly', + BigUint64Array: 'readonly', + CacheType: 'readonly', + Class: 'readonly', + ClientRect: 'readonly', + CopyInspectedElementPath: 'readonly', + DOMHighResTimeStamp: 'readonly', + EventListener: 'readonly', + // Flow type + FormDataEntryValue: 'readonly', + Iterable: 'readonly', + AsyncIterable: 'readonly', + $AsyncIterable: 'readonly', + $AsyncIterator: 'readonly', + Iterator: 'readonly', + AsyncIterator: 'readonly', + IntervalID: 'readonly', + IteratorResult: 'readonly', + JSONValue: 'readonly', + JSResourceReference: 'readonly', + mixin$Animatable: 'readonly', + MouseEventHandler: 'readonly', + NavigateEvent: 'readonly', + Partial: 'readonly', + PerformanceMeasureOptions: 'readonly', + PropagationPhases: 'readonly', + PropertyDescriptor: 'readonly', + PropertyDescriptorMap: 'readonly', + Proxy$traps: 'readonly', + React$Component: 'readonly', + React$Config: 'readonly', + React$Context: 'readonly', + React$Element: 'readonly', + React$ElementConfig: 'readonly', + React$ElementProps: 'readonly', + React$ElementRef: 'readonly', + React$ElementType: 'readonly', + React$Key: 'readonly', + React$Node: 'readonly', + React$Portal: 'readonly', + React$Ref: 'readonly', + React$RefSetter: 'readonly', + ReadableStreamController: 'readonly', + ReadableStreamReader: 'readonly', + RequestInfo: 'readonly', + RequestOptions: 'readonly', + Required: 'readonly', + StoreAsGlobal: 'readonly', + symbol: 'readonly', + SyntheticEvent: 'readonly', + SyntheticMouseEvent: 'readonly', + SyntheticPointerEvent: 'readonly', + Thenable: 'readonly', + TimeoutID: 'readonly', + WheelEventHandler: 'readonly', + FinalizationRegistry: 'readonly', + Exclude: 'readonly', + Omit: 'readonly', + Pick: 'readonly', + Keyframe: 'readonly', + PropertyIndexedKeyframes: 'readonly', + KeyframeAnimationOptions: 'readonly', + GetAnimationsOptions: 'readonly', + ScrollTimeline: 'readonly', + EventListenerOptionsOrUseCapture: 'readonly', + FocusOptions: 'readonly', + OptionalEffectTiming: 'readonly', + + __REACT_ROOT_PATH_TEST__: 'readonly', + spyOnDev: 'readonly', + spyOnDevAndProd: 'readonly', + spyOnProd: 'readonly', + __DEV__: 'readonly', + __EXPERIMENTAL__: 'readonly', + __EXTENSION__: 'readonly', + __PROFILE__: 'readonly', + __TEST__: 'readonly', + __VARIANT__: 'readonly', + __unmockReact: 'readonly', + gate: 'readonly', + trustedTypes: 'readonly', + IS_REACT_ACT_ENVIRONMENT: 'readonly', + AsyncLocalStorage: 'readonly', + async_hooks: 'readonly', + globalThis: 'readonly', + navigation: 'readonly', }, }; diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000000..2c19b2484595 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +c998bb1ed4b3285398c9c7797135d3f060243c6a +fd2b3e13d330a4559f5aa21462e1cb2cbbcf144b diff --git a/.github/ISSUE_TEMPLATE/compiler_bug_report.yml b/.github/ISSUE_TEMPLATE/compiler_bug_report.yml new file mode 100644 index 000000000000..a2c0e3d7aa38 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/compiler_bug_report.yml @@ -0,0 +1,64 @@ +name: "โš›๏ธ โœจ Compiler bug report" +description: "Report a problem with React Compiler. Please provide enough information that we can reproduce the problem." +title: "[Compiler Bug]: " +labels: ["Component: Optimizing Compiler", "Type: Bug", "Status: Unconfirmed"] +body: +- type: checkboxes + attributes: + label: What kind of issue is this? + description: | + Please indicate if this issue affects the following tools provided by React Compiler. + options: + - label: React Compiler core (the JS output is incorrect, or your app works incorrectly after optimization) + - label: babel-plugin-react-compiler (build issue installing or using the Babel plugin) + - label: eslint-plugin-react-hooks (build issue installing or using the eslint plugin) + - label: react-compiler-healthcheck (build issue installing or using the healthcheck script) +- type: input + attributes: + label: Link to repro + description: | + Please provide a repro by either sharing a [Playground link](https://playground.react.dev), or a public GitHub repo so the React team can reproduce the error being reported. Please do not share localhost links! + placeholder: | + e.g. public GitHub repo, or Playground link + validations: + required: true +- type: textarea + attributes: + label: Repro steps + description: | + What were you doing when the bug happened? Detailed information helps maintainers reproduce and fix bugs. + + Issues filed without repro steps will be closed. + placeholder: | + Example bug report: + 1. Log in with username/password + 2. Click "Messages" on the left menu + 3. Open any message in the list + validations: + required: true +- type: dropdown + attributes: + label: How often does this bug happen? + description: | + Following the repro steps above, how easily are you able to reproduce this bug? + options: + - Every time + - Often + - Sometimes + - Only once + validations: + required: true +- type: input + attributes: + label: What version of React are you using? + description: | + Please provide your React version in the app where this issue occurred. + validations: + required: true +- type: input + attributes: + label: What version of React Compiler are you using? + description: | + Please provide the exact React Compiler version in the app where this issue occurred. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e5bb31b2b378..2b1404175e69 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,6 +1,7 @@ +blank_issues_enabled: false contact_links: - name: ๐Ÿ“ƒ Documentation Issue - url: https://github.com/reactjs/reactjs.org/issues/new + url: https://github.com/reactjs/react.dev/issues/new/choose about: This issue tracker is not for documentation issues. Please file documentation issues here. - name: ๐Ÿค” Questions and Help url: https://reactjs.org/community/support.html diff --git a/.github/ISSUE_TEMPLATE/devtools_bug_report.yml b/.github/ISSUE_TEMPLATE/devtools_bug_report.yml new file mode 100644 index 000000000000..f90209764681 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/devtools_bug_report.yml @@ -0,0 +1,81 @@ +name: "โš›๏ธ ๐Ÿ›  DevTools bug report" +description: "Report a problem with React DevTools. Please provide enough information that we can reproduce the problem." +title: "[DevTools Bug]: " +labels: ["Component: Developer Tools", "Type: Bug", "Status: Unconfirmed"] +body: +- type: input + attributes: + label: Website or app + description: | + Which website or app were you using when the bug happened? + + This should be a public URL, GitHub repo, or Code Sandbox app so the React team can reproduce the error being reported. (Please no localhost URLs.) + placeholder: | + e.g. website URL, public GitHub repo, or Code Sandbox app + validations: + required: true +- type: textarea + attributes: + label: Repro steps + description: | + What were you doing on the website or app when the bug happened? Detailed information helps maintainers reproduce and fix bugs. + + Issues filed without repro steps will be closed. + placeholder: | + Example bug report: + 1. Log in with username/password + 2. Click "Messages" on the left menu + 3. Open any message in the list + validations: + required: true +- type: dropdown + attributes: + label: How often does this bug happen? + description: | + Following the repro steps above, how easily are you able to reproduce this bug? + options: + - Every time + - Often + - Sometimes + - Only once + validations: + required: true +- type: input + id: automated_package + attributes: + label: DevTools package (automated) + description: | + Please do not edit this field. +- type: input + id: automated_version + attributes: + label: DevTools version (automated) + description: | + Please do not edit this field. +- type: input + id: automated_error_message + attributes: + label: Error message (automated) + description: | + Please do not edit this field. +- type: textarea + id: automated_call_stack + attributes: + label: Error call stack (automated) + description: | + Please do not edit this field. + render: text +- type: textarea + id: automated_component_stack + attributes: + label: Error component stack (automated) + description: | + Please do not edit this field. + render: text +- type: textarea + id: automated_github_query_string + attributes: + label: GitHub query string (automated) + description: | + Please do not edit this field. + render: text diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7759363adb33..23fbc65ab576 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,12 +4,12 @@ Before submitting a pull request, please make sure the following is done: - 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `master`. + 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. - 5. Run `yarn test-prod` to test in the production environment. It supports the same options as `yarn test`. - 6. If you need a debugger, run `yarn debug-test --watch TestName`, open `chrome://inspect`, and press "Inspect". + 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. + 6. If you need a debugger, run `yarn test --debug --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). @@ -20,8 +20,14 @@ ## Summary - + -## Test Plan +## How did you test this change? - + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..11800ad75759 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directories: + - "/fixtures/*" + schedule: + interval: "monthly" + open-pull-requests-limit: 0 + ignore: + - dependency-name: "*" diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 25f65e7c3d4a..000000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 90 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - "Partner" - - "React Core Team" - - "Resolution: Backlog" - - "Type: Bug" - - "Type: Discussion" - - "Type: Needs Investigation" - - "Type: Regression" -# Label to use when marking an issue as stale -staleLabel: "Resolution: Stale" -issues: - # Comment to post when marking an issue as stale. - markComment: > - This issue has been automatically marked as stale. - **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. - We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! - # Comment to post when closing a stale issue. - closeComment: > - Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you! -pulls: - # Comment to post when marking a pull request as stale. - markComment: > - This pull request has been automatically marked as stale. - **If this pull request is still relevant, please leave any comment** (for example, "bump"), and we'll keep it open. - We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated. - # Comment to post when closing a stale pull request. - closeComment: > - Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you! diff --git a/.github/workflows/compiler_discord_notify.yml b/.github/workflows/compiler_discord_notify.yml new file mode 100644 index 000000000000..8d0a698c24f0 --- /dev/null +++ b/.github/workflows/compiler_discord_notify.yml @@ -0,0 +1,49 @@ +name: (Compiler) Discord Notify + +on: + pull_request_target: + types: [opened, ready_for_review] + paths: + - compiler/** + - .github/workflows/compiler_**.yml + +permissions: {} + +jobs: + check_access: + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-latest + outputs: + is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }} + steps: + - run: echo ${{ github.event.pull_request.author_association }} + - name: Check is member or collaborator + id: check_is_member_or_collaborator + if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }} + run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT" + + check_maintainer: + if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }} + needs: [check_access] + uses: react/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read + with: + actor: ${{ github.event.pull_request.user.login }} + + notify: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + needs: check_maintainer + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.COMPILER_DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.pull_request.user.login }} + embed-author-url: ${{ github.event.pull_request.user.html_url }} + embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }} + embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}' + embed-description: ${{ github.event.pull_request.body }} + embed-url: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml new file mode 100644 index 000000000000..c7a802c9b969 --- /dev/null +++ b/.github/workflows/compiler_playground.yml @@ -0,0 +1,67 @@ +name: (Compiler) Playground + +on: + push: + branches: [main] + pull_request: + paths: + - compiler/** + - .github/workflows/compiler_playground.yml + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +defaults: + run: + working-directory: compiler/apps/playground + +jobs: + playground: + name: Test playground + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: compiler-and-playground-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + working-directory: compiler + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Check Playwright version + id: playwright_version + run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT" + - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }} + id: cache_playwright_browsers + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }} + - run: npx playwright install --with-deps chromium + if: steps.cache_playwright_browsers.outputs.cache-hit != 'true' + - run: CI=true yarn test + - run: ls -R test-results + if: '!cancelled()' + - name: Archive test results + if: '!cancelled()' + uses: actions/upload-artifact@v4 + with: + name: test-results + path: compiler/apps/playground/test-results + if-no-files-found: ignore diff --git a/.github/workflows/compiler_prereleases.yml b/.github/workflows/compiler_prereleases.yml new file mode 100644 index 000000000000..e4b44832feff --- /dev/null +++ b/.github/workflows/compiler_prereleases.yml @@ -0,0 +1,68 @@ +name: (Compiler) Publish Prereleases + +on: + workflow_call: + inputs: + commit_sha: + required: true + default: '' + type: string + release_channel: + required: true + type: string + dist_tag: + required: true + type: string + version_name: + required: true + type: string + tag_version: + required: false + type: string + dry_run: + required: false + type: boolean + secrets: + NPM_TOKEN: + required: true + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + +defaults: + run: + working-directory: compiler + +jobs: + publish_prerelease: + name: Publish prelease (${{ inputs.release_channel }}) ${{ inputs.commit_sha }} @${{ inputs.dist_tag }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - if: inputs.dry_run == true + name: Publish packages to npm (dry run) + run: | + cp ./scripts/release/ci-npmrc ~/.npmrc + scripts/release/publish.js --frfr --debug --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }} + - if: inputs.dry_run != true + name: Publish packages to npm + run: | + cp ./scripts/release/ci-npmrc ~/.npmrc + scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }} diff --git a/.github/workflows/compiler_prereleases_manual.yml b/.github/workflows/compiler_prereleases_manual.yml new file mode 100644 index 000000000000..5d138d82ed71 --- /dev/null +++ b/.github/workflows/compiler_prereleases_manual.yml @@ -0,0 +1,41 @@ +name: (Compiler) Publish Prereleases Manual + +on: + workflow_dispatch: + inputs: + prerelease_commit_sha: + required: false + release_channel: + required: true + type: string + dist_tag: + required: true + type: string + version_name: + required: true + type: string + tag_version: + required: false + type: string + dry_run: + required: false + type: boolean + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + publish_prerelease_experimental: + name: Publish to Experimental channel + uses: react/react/.github/workflows/compiler_prereleases.yml@main + with: + commit_sha: ${{ inputs.prerelease_commit_sha || github.sha }} + release_channel: ${{ inputs.release_channel }} + dist_tag: ${{ inputs.dist_tag }} + version_name: ${{ inputs.version_name }} + tag_version: ${{ inputs.tag_version }} + dry_run: ${{ inputs.dry_run }} + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/compiler_prereleases_nightly.yml b/.github/workflows/compiler_prereleases_nightly.yml new file mode 100644 index 000000000000..813cfa0c7cd7 --- /dev/null +++ b/.github/workflows/compiler_prereleases_nightly.yml @@ -0,0 +1,24 @@ +name: (Compiler) Publish Prereleases Nightly + +on: + schedule: + # At 10 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri + - cron: 10 16 * * 1,2,3,4,5 + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + publish_prerelease_experimental: + name: Publish to Experimental channel + uses: react/react/.github/workflows/compiler_prereleases.yml@main + with: + commit_sha: ${{ github.sha }} + release_channel: experimental + dist_tag: experimental + version_name: '0.0.0' + dry_run: false + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/compiler_rust.yml b/.github/workflows/compiler_rust.yml new file mode 100644 index 000000000000..0fd373c08c0b --- /dev/null +++ b/.github/workflows/compiler_rust.yml @@ -0,0 +1,68 @@ +name: React Compiler (Rust) + +on: + push: + branches: [main] + pull_request: + paths: + - compiler/** + - .github/workflows/compiler_rust.yml + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +defaults: + run: + working-directory: compiler + +jobs: + rust: + name: Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # --- Rust toolchain --- + - uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry and build + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + compiler/target + key: cargo-${{ runner.os }}-${{ hashFiles('compiler/Cargo.lock') }} + restore-keys: cargo-${{ runner.os }}- + + # --- Node (needed for test scripts) --- + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: yarn + cache-dependency-path: compiler/yarn.lock + + - name: Restore cached node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: '**/node_modules' + key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }} + + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + + # --- Build & test --- + - run: cargo check + - run: cargo build + - run: bash scripts/test-babel-ast.sh + - run: bash scripts/test-rust-port.sh + - run: yarn workspace snap run build + - run: yarn snap --rust diff --git a/.github/workflows/compiler_typescript.yml b/.github/workflows/compiler_typescript.yml new file mode 100644 index 000000000000..db043d7800f8 --- /dev/null +++ b/.github/workflows/compiler_typescript.yml @@ -0,0 +1,104 @@ +name: (Compiler) TypeScript + +on: + push: + branches: [main] + pull_request: + paths: + - compiler/** + - .github/workflows/compiler_typescript.yml + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +defaults: + run: + working-directory: compiler + +jobs: + discover_yarn_workspaces: + name: Discover yarn workspaces + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + - id: set-matrix + run: echo "matrix=$(find packages -mindepth 1 -maxdepth 1 -type d | sed 's!packages/!!g' | tr '\n' ',' | sed s/.$// | jq -Rsc '. / "," - [""]')" >> $GITHUB_OUTPUT + + # Hardcoded to improve parallelism + lint: + name: Lint babel-plugin-react-compiler + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: yarn + cache-dependency-path: compiler/yarn.lock + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn workspace babel-plugin-react-compiler lint + + # Hardcoded to improve parallelism + jest: + name: Jest babel-plugin-react-compiler + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn workspace babel-plugin-react-compiler jest + + test: + name: Test ${{ matrix.workspace_name }} + needs: discover_yarn_workspaces + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + workspace_name: ${{ fromJSON(needs.discover_yarn_workspaces.outputs.matrix) }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test + if: runner.os == 'Linux' && matrix.workspace_name == 'react-forgive' + - run: yarn workspace ${{ matrix.workspace_name }} test + if: matrix.workspace_name != 'react-forgive' diff --git a/.github/workflows/devtools_discord_notify.yml b/.github/workflows/devtools_discord_notify.yml new file mode 100644 index 000000000000..a4b711131c9a --- /dev/null +++ b/.github/workflows/devtools_discord_notify.yml @@ -0,0 +1,49 @@ +name: (DevTools) Discord Notify + +on: + pull_request_target: + types: [opened, ready_for_review] + paths: + - packages/react-devtools** + - .github/workflows/devtools_**.yml + +permissions: {} + +jobs: + check_access: + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-latest + outputs: + is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }} + steps: + - run: echo ${{ github.event.pull_request.author_association }} + - name: Check is member or collaborator + id: check_is_member_or_collaborator + if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }} + run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT" + + check_maintainer: + if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }} + needs: [check_access] + uses: react/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read + with: + actor: ${{ github.event.pull_request.user.login }} + + notify: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + needs: check_maintainer + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.DEVTOOLS_DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.pull_request.user.login }} + embed-author-url: ${{ github.event.pull_request.user.html_url }} + embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }} + embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}' + embed-description: ${{ github.event.pull_request.body }} + embed-url: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml new file mode 100644 index 000000000000..add860717d2f --- /dev/null +++ b/.github/workflows/devtools_regression_tests.yml @@ -0,0 +1,197 @@ +name: (DevTools) Regression Tests + +on: + schedule: + - cron: 0 0 * * * + workflow_dispatch: + inputs: + commit_sha: + required: false + type: string + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + download_build: + name: Download base build + runs-on: ubuntu-latest + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd scripts/release install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Download react-devtools artifacts for base revision + run: | + git fetch origin main + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || '$(git rev-parse origin/main)' }} + - name: Display structure of build + run: ls -R build + - name: Archive build + uses: actions/upload-artifact@v4 + with: + name: build + path: build + if-no-files-found: error + + build_devtools_and_process_artifacts: + name: Build DevTools and process artifacts + needs: download_build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + name: build + path: build + - run: ./scripts/ci/pack_and_store_devtools_artifacts.sh + env: + RELEASE_CHANNEL: experimental + - name: Display structure of build + run: ls -R build + - name: Archive devtools build + uses: actions/upload-artifact@v4 + with: + name: react-devtools + path: build/devtools + if-no-files-found: error + # Simplifies getting the extension for local testing + - name: Archive chrome extension + uses: actions/upload-artifact@v4 + with: + name: react-devtools-chrome-extension + path: build/devtools/chrome-extension.zip + if-no-files-found: error + - name: Archive firefox extension + uses: actions/upload-artifact@v4 + with: + name: react-devtools-firefox-extension + path: build/devtools/firefox-extension.zip + if-no-files-found: error + + run_devtools_tests_for_versions: + name: Run DevTools tests for versions + needs: build_devtools_and_process_artifacts + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + version: + - "16.0" + - "16.5" # schedule package + - "16.8" # hooks + - "17.0" + - "18.0" + - "18.2" # compiler polyfill + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore all archived build artifacts + uses: actions/download-artifact@v4 + - name: Display structure of build + run: ls -R build + - run: ./scripts/ci/download_devtools_regression_build.js ${{ matrix.version }} --replaceBuild + - run: node ./scripts/jest/jest-cli.js --build --project devtools --release-channel=experimental --reactVersion ${{ matrix.version }} --ci + + run_devtools_e2e_tests_for_versions: + name: Run DevTools e2e tests for versions + needs: build_devtools_and_process_artifacts + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + version: + - "16.0" + - "16.5" # schedule package + - "16.8" # hooks + - "17.0" + - "18.0" + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore all archived build artifacts + uses: actions/download-artifact@v4 + - name: Display structure of build + run: ls -R build + - name: Check Playwright version + id: playwright_version + run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT" + - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }} + id: cache_playwright_browsers + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }} + - run: npx playwright install --with-deps + if: steps.cache_playwright_browsers.outputs.cache-hit != 'true' + - run: npx playwright install-deps + if: steps.cache_playwright_browsers.outputs.cache-hit == 'true' + - run: ./scripts/ci/download_devtools_regression_build.js ${{ matrix.version }} + - run: ls -R build-regression + - run: ./scripts/ci/run_devtools_e2e_tests.js ${{ matrix.version }} + env: + RELEASE_CHANNEL: experimental + - name: Cleanup build regression folder + run: rm -r ./build-regression + - uses: actions/upload-artifact@v4 + with: + name: screenshots + path: ./tmp/playwright-artifacts + if-no-files-found: warn diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml new file mode 100644 index 000000000000..2c91491da19e --- /dev/null +++ b/.github/workflows/runtime_build_and_test.yml @@ -0,0 +1,939 @@ +name: (Runtime) Build and Test + +on: + push: + branches: + # release branches (keep in sync with branches that receive artifact attestations) + - main + - releases/** + pull_request: + paths-ignore: + - compiler/** + # Manual re-runs are allowed. The workflow always runs on the SHA it was + # dispatched from (github.sha); no user-supplied ref is accepted, because + # downstream workflows (e.g. runtime_release_from_ci) consume this + # workflow's artifacts under a protected environment. + workflow_dispatch: + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + # ----- NODE_MODULES CACHE ----- + # Centralize the node_modules cache so it is saved once and each subsequent job only needs to + # restore the cache. Prevents race conditions where multiple workflows try to write to the cache. + runtime_node_modules_cache: + name: Cache Runtime node_modules + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Prepare cache + id: node_modules + uses: actions/cache@v4 + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + + - uses: actions/setup-node@v4 + if: steps.node_modules.outputs.cache-hit != 'true' + with: + node-version-file: '.nvmrc' + + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + + runtime_compiler_node_modules_cache: + name: Cache Runtime, Compiler node_modules + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Prepare cache + id: node_modules + uses: actions/cache@v4 + with: + path: | + **/node_modules + key: runtime-and-compiler-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd compiler install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + + # ----- FLOW ----- + discover_flow_inline_configs: + name: Discover flow inline configs + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.result }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/github-script@v7 + id: set-matrix + with: + script: | + const inlinedHostConfigs = require('./scripts/shared/inlinedHostConfigs.js'); + return inlinedHostConfigs.map(config => config.shortName); + + flow: + name: Flow check ${{ matrix.flow_inline_config_shortname }} + needs: [discover_flow_inline_configs, runtime_node_modules_cache] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + flow_inline_config_shortname: ${{ fromJSON(needs.discover_flow_inline_configs.outputs.matrix) }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }} + + # ----- FIZZ ----- + check_generated_fizz_runtime: + name: Confirm generated inline Fizz runtime is up to date + needs: [runtime_node_modules_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: | + yarn generate-inline-fizz-runtime + git diff --exit-code || (echo "There was a change to the Fizz runtime. Run \`yarn generate-inline-fizz-runtime\` and check in the result." && false) + + # ----- FEATURE FLAGS ----- + flags: + name: Check flags + needs: [runtime_node_modules_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn flags + + # ----- TESTS ----- + test: + name: yarn test ${{ matrix.params }} (Shard ${{ matrix.shard }}) + needs: [runtime_compiler_node_modules_cache] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + params: + - "-r=stable --env=development" + - "-r=stable --env=production" + - "-r=experimental --env=development" + - "-r=experimental --env=production" + - "-r=www-classic --env=development --variant=false" + - "-r=www-classic --env=production --variant=false" + - "-r=www-classic --env=development --variant=true" + - "-r=www-classic --env=production --variant=true" + - "-r=www-modern --env=development --variant=false" + - "-r=www-modern --env=production --variant=false" + - "-r=www-modern --env=development --variant=true" + - "-r=www-modern --env=production --variant=true" + - "-r=xplat --env=development --variant=false" + - "-r=xplat --env=development --variant=true" + - "-r=xplat --env=production --variant=false" + - "-r=xplat --env=production --variant=true" + # TODO: Test more persistent configurations? + - "-r=stable --env=development --persistent" + - "-r=experimental --env=development --persistent" + shard: + - 1/5 + - 2/5 + - 3/5 + - 4/5 + - 5/5 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-and-compiler-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd compiler install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: node --version + - run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }} + + # Hardcoded to improve parallelism + test-linter: + name: Test eslint-plugin-react-hooks + needs: [runtime_compiler_node_modules_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-and-compiler-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + - name: Install runtime dependencies + run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Install compiler dependencies + run: yarn install --frozen-lockfile + working-directory: compiler + if: steps.node_modules.outputs.cache-hit != 'true' + - run: ./scripts/react-compiler/build-compiler.sh && ./scripts/react-compiler/link-compiler.sh + - run: yarn workspace eslint-plugin-react-hooks test + + # ----- BUILD ----- + build_and_lint: + name: yarn build and lint + needs: [runtime_compiler_node_modules_cache] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # yml is dumb. update the --total arg to yarn build if you change the number of workers + worker_id: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24] + release_channel: [stable, experimental] + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 11.0.22 + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-and-compiler-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd compiler install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn build --index=${{ matrix.worker_id }} --total=25 --r=${{ matrix.release_channel }} --ci + env: + CI: github + RELEASE_CHANNEL: ${{ matrix.release_channel }} + NODE_INDEX: ${{ matrix.worker_id }} + - name: Lint build + run: yarn lint-build + - name: Display structure of build + run: ls -R build + - name: Archive build + uses: actions/upload-artifact@v4 + with: + name: _build_${{ matrix.worker_id }}_${{ matrix.release_channel }} + path: build + if-no-files-found: error + + test_build: + name: yarn test-build + needs: [build_and_lint, runtime_compiler_node_modules_cache] + strategy: + fail-fast: false + matrix: + test_params: [ + # Intentionally passing these as strings instead of creating a + # separate parameter per CLI argument, since it's easier to + # control/see which combinations we want to run. + -r=stable --env=development, + -r=stable --env=production, + -r=experimental --env=development, + -r=experimental --env=production, + + # TODO: Update test config to support www build tests + # - "-r=www-classic --env=development --variant=false" + # - "-r=www-classic --env=production --variant=false" + # - "-r=www-classic --env=development --variant=true" + # - "-r=www-classic --env=production --variant=true" + # - "-r=www-modern --env=development --variant=false" + # - "-r=www-modern --env=production --variant=false" + # - "-r=www-modern --env=development --variant=true" + # - "-r=www-modern --env=production --variant=true" + + # TODO: Update test config to support xplat build tests + # - "-r=xplat --env=development --variant=false" + # - "-r=xplat --env=development --variant=true" + # - "-r=xplat --env=production --variant=false" + # - "-r=xplat --env=production --variant=true" + + # TODO: Test more persistent configurations? + ] + shard: + - 1/10 + - 2/10 + - 3/10 + - 4/10 + - 5/10 + - 6/10 + - 7/10 + - 8/10 + - 9/10 + - 10/10 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-and-compiler-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd compiler install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - run: node --version + - run: yarn test --build ${{ matrix.test_params }} --shard=${{ matrix.shard }} --ci + + test_build_devtools: + name: yarn test-build (devtools) + needs: [build_and_lint, runtime_node_modules_cache] + strategy: + fail-fast: false + matrix: + shard: + - 1/5 + - 2/5 + - 3/5 + - 4/5 + - 5/5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - run: node --version + - run: yarn test --build --project=devtools -r=experimental --shard=${{ matrix.shard }} --ci + + process_artifacts_combined: + name: Process artifacts combined + needs: [build_and_lint, runtime_node_modules_cache] + permissions: + # https://github.com/actions/attest-build-provenance + id-token: write + attestations: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA + - name: Scrape warning messages + run: | + mkdir -p ./build/__test_utils__ + node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js + # Compress build directory into a single tarball for easy download + - run: tar -zcvf ./build.tgz ./build + # TODO: Migrate scripts to use `build` directory instead of `build2` + - run: cp ./build.tgz ./build2.tgz + - name: Archive build artifacts + id: upload_artifacts_combined + uses: actions/upload-artifact@v4 + with: + name: artifacts_combined + path: | + ./build.tgz + ./build2.tgz + if-no-files-found: error + - uses: actions/attest-build-provenance@v2 + # We don't verify builds generated from pull requests not originating from react/react. + # However, if the PR lands, the run on release branches will generate the attestation which can then + # be used to download a build via scripts/release/download-experimental-build.js. + # + # Note that this means that scripts/release/download-experimental-build.js must be run with + # --no-verify when downloading a build from a fork. + if: github.event_name == 'push' && (github.ref_name == 'main' || startsWith(github.ref_name, 'releases/')) || github.event.pull_request.head.repo.full_name == github.repository + with: + subject-name: artifacts_combined.zip + subject-digest: sha256:${{ steps.upload_artifacts_combined.outputs.artifact-digest }} + + check_error_codes: + name: Search build artifacts for unminified errors + needs: [build_and_lint, runtime_node_modules_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - name: Search build artifacts for unminified errors + run: | + yarn extract-errors + git diff --exit-code || (echo "Found unminified errors. Either update the error codes map or disable error minification for the affected build, if appropriate." && false) + + check_release_dependencies: + name: Check release dependencies + needs: [build_and_lint, runtime_node_modules_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - run: yarn check-release-dependencies + + RELEASE_CHANNEL_stable_yarn_test_dom_fixtures: + name: Check fixtures DOM (stable) + needs: build_and_lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key + id: node_modules + with: + path: | + **/node_modules + key: fixtures_dom-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/dom/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn --cwd fixtures/dom install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - name: Run DOM fixture tests + run: | + yarn predev + yarn test + working-directory: fixtures/dom + env: + RELEASE_CHANNEL: stable + + # ----- FLIGHT ----- + run_fixtures_flight_tests: + name: Run fixtures Flight tests + needs: build_and_lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + # Fixture copies some built packages from the workroot after install. + # That means dependencies of the built packages are not installed. + # We need to install dependencies of the workroot to fulfill all dependency constraints + - name: Restore cached node_modules + uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key + id: node_modules + with: + path: | + **/node_modules + key: fixtures_flight-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/flight/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd fixtures/flight install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Check Playwright version + id: playwright_version + run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT" + - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }} + id: cache_playwright_browsers + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }} + - name: Playwright install deps + if: steps.cache_playwright_browsers.outputs.cache-hit != 'true' + working-directory: fixtures/flight + run: npx playwright install --with-deps chromium + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - name: Run tests + working-directory: fixtures/flight + run: yarn test + env: + # Otherwise the webserver is a blackbox + DEBUG: pw:webserver + - name: Archive Flight fixture artifacts + uses: actions/upload-artifact@v4 + with: + name: flight-playwright-report + path: fixtures/flight/playwright-report + if-no-files-found: warn + - name: Archive Flight fixture artifacts + uses: actions/upload-artifact@v4 + with: + name: flight-test-results + path: fixtures/flight/test-results + if-no-files-found: ignore + + # ----- DEVTOOLS ----- + build_devtools_and_process_artifacts: + name: Build DevTools and process artifacts + needs: [build_and_lint, runtime_node_modules_cache] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + browser: [chrome, firefox, edge] + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - run: ./scripts/ci/pack_and_store_devtools_artifacts.sh ${{ matrix.browser }} + env: + RELEASE_CHANNEL: experimental + - name: Display structure of build + run: ls -R build + # Simplifies getting the extension for local testing + - name: Archive ${{ matrix.browser }} extension + uses: actions/upload-artifact@v4 + with: + name: react-devtools-${{ matrix.browser }}-extension + path: build/devtools/${{ matrix.browser }}-extension.zip + if-no-files-found: error + - name: Archive ${{ matrix.browser }} metadata + uses: actions/upload-artifact@v4 + with: + name: react-devtools-${{ matrix.browser }}-metadata + path: build/devtools/webpack-stats.*.json + + merge_devtools_artifacts: + name: Merge DevTools artifacts + needs: build_devtools_and_process_artifacts + runs-on: ubuntu-latest + steps: + - name: Merge artifacts + uses: actions/upload-artifact/merge@v4 + with: + name: react-devtools + pattern: react-devtools-* + + runtime_playwright_chromium_cache: + name: Cache Runtime Playwright Chromium + needs: runtime_node_modules_cache + runs-on: ubuntu-latest + outputs: + playwright_version: ${{ steps.playwright_version.outputs.playwright_version }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Check Playwright version + id: playwright_version + run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT" + - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }} + id: cache_playwright_browsers + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }} + - name: Install Playwright Chromium + if: steps.cache_playwright_browsers.outputs.cache-hit != 'true' + run: npx playwright install chromium + + run_devtools_e2e_tests: + name: Run React DevTools browser extension e2e tests + needs: [build_and_lint, runtime_playwright_chromium_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Restore Playwright Chromium + uses: actions/cache/restore@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ needs.runtime_playwright_chromium_cache.outputs.playwright_version }} + fail-on-cache-miss: true + - run: ./scripts/ci/run_devtools_e2e_tests.js + env: + RELEASE_CHANNEL: experimental + - name: Archive Playwright report + uses: actions/upload-artifact@v4 + with: + name: devtools-playwright-artifacts + path: tmp/playwright-artifacts + if-no-files-found: warn + + run_react_devtools_cdt_mcp_e2e_tests: + name: Run react-devtools-cdt-mcp e2e tests + needs: [build_and_lint, runtime_playwright_chromium_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v10-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Restore Playwright Chromium + uses: actions/cache/restore@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ needs.runtime_playwright_chromium_cache.outputs.playwright_version }} + fail-on-cache-miss: true + - name: Check Playwright Chromium version + id: playwright_chromium + run: | + echo "executable_path=$(node -e 'process.stdout.write(require("playwright").chromium.executablePath())')" >> "$GITHUB_OUTPUT" + "$(node -e 'process.stdout.write(require("playwright").chromium.executablePath())')" --version + - name: Run React DevTools CDT MCP e2e tests + run: yarn --cwd packages/react-devtools-cdt-mcp test:e2e:ci + env: + CHROME_EXECUTABLE_PATH: ${{ steps.playwright_chromium.outputs.executable_path }} + - name: Archive React DevTools CDT MCP e2e logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: react-devtools-cdt-mcp-e2e-logs + path: tmp/react-devtools-cdt-mcp-e2e + if-no-files-found: warn + + # ----- SIZEBOT ----- + sizebot: + if: ${{ github.event_name == 'pull_request' && github.ref_name != 'main' && github.event.pull_request.base.ref == 'main' }} + name: Run sizebot + needs: [build_and_lint] + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key + id: node_modules + with: + path: | + **/node_modules + key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd scripts/release install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Download artifacts for base revision + # The build could have been generated from a fork, so we must download the build without + # any verification. This is safe since we only use this for sizebot calculation and the + # unverified artifact is not used. Additionally this workflow runs in the pull_request + # trigger so only restricted permissions are available. + run: | + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse ${{ github.event.pull_request.base.sha }}) ${{ (github.event.pull_request.head.repo.full_name != github.repository && '--noVerify') || ''}} + mv ./build ./base-build + - name: Delete extraneous files + # TODO: The `download-experimental-build` script copies the npm + # packages into the `node_modules` directory. This is a historical + # quirk of how the release script works. Let's pretend they + # don't exist. + run: rm -rf ./base-build/node_modules + - name: Display structure of base-build from origin/main + run: ls -R base-build + - name: Ensure clean build directory + run: rm -rf build + - name: Restore archived build for PR + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Scrape warning messages + run: | + mkdir -p ./build/__test_utils__ + node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js + - name: Display structure of build for PR + run: ls -R build + - run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA + - run: node ./scripts/tasks/danger + - name: Archive sizebot results + uses: actions/upload-artifact@v4 + with: + name: sizebot-message + path: sizebot-message.md + if-no-files-found: ignore diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml new file mode 100644 index 000000000000..96a15ba7fb12 --- /dev/null +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -0,0 +1,472 @@ +name: (Runtime) Commit Artifacts for Meta WWW and fbsource V2 + +on: + workflow_run: + workflows: ["(Runtime) Build and Test"] + types: [completed] + branches: + - main + workflow_dispatch: + inputs: + commit_sha: + required: false + type: string + force: + description: 'Force a commit to the builds/... branches' + required: true + default: false + type: boolean + dry_run: + description: Perform a dry run (run everything except push) + required: true + default: false + type: boolean + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + download_artifacts: + runs-on: ubuntu-latest + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read + steps: + - uses: actions/checkout@v4 + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd scripts/release install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Download artifacts for base revision + run: | + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} + - name: Display structure of build + run: ls -R build + - name: Archive build + uses: actions/upload-artifact@v4 + with: + name: build + path: build/ + if-no-files-found: error + + + process_artifacts: + runs-on: ubuntu-latest + needs: [download_artifacts] + outputs: + www_branch_count: ${{ steps.check_branches.outputs.www_branch_count }} + fbsource_branch_count: ${{ steps.check_branches.outputs.fbsource_branch_count }} + last_version_classic: ${{ steps.get_last_version_www.outputs.last_version_classic }} + last_version_modern: ${{ steps.get_last_version_www.outputs.last_version_modern }} + last_version_rn: ${{ steps.get_last_version_rn.outputs.last_version_rn }} + current_version_classic: ${{ steps.get_current_version.outputs.current_version_classic }} + current_version_modern: ${{ steps.get_current_version.outputs.current_version_modern }} + current_version_rn: ${{ steps.get_current_version.outputs.current_version_rn }} + steps: + - uses: actions/checkout@v4 + with: + ref: builds/facebook-www + - name: "Get last version string for www" + id: get_last_version_www + run: | + # Empty checks only needed for backwards compatibility,can remove later. + VERSION_CLASSIC=$( [ -f ./compiled/facebook-www/VERSION_CLASSIC ] && cat ./compiled/facebook-www/VERSION_CLASSIC || echo '' ) + VERSION_MODERN=$( [ -f ./compiled/facebook-www/VERSION_MODERN ] && cat ./compiled/facebook-www/VERSION_MODERN || echo '' ) + echo "Last classic version is $VERSION_CLASSIC" + echo "Last modern version is $VERSION_MODERN" + echo "last_version_classic=$VERSION_CLASSIC" >> "$GITHUB_OUTPUT" + echo "last_version_modern=$VERSION_MODERN" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v4 + with: + ref: builds/facebook-fbsource + - name: "Get last version string for rn" + id: get_last_version_rn + run: | + # Empty checks only needed for backwards compatibility,can remove later. + VERSION_NATIVE_FB=$( [ -f ./compiled-rn/VERSION_NATIVE_FB ] && cat ./compiled-rn/VERSION_NATIVE_FB || echo '' ) + echo "Last rn version is $VERSION_NATIVE_FB" + echo "last_version_rn=$VERSION_NATIVE_FB" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v4 + - name: "Check branches" + id: check_branches + run: | + echo "www_branch_count=$(git ls-remote --heads origin "refs/heads/meta-www" | wc -l)" >> "$GITHUB_OUTPUT" + echo "fbsource_branch_count=$(git ls-remote --heads origin "refs/heads/meta-fbsource" | wc -l)" >> "$GITHUB_OUTPUT" + - name: Restore downloaded build + uses: actions/download-artifact@v4 + with: + name: build + path: build + - name: Display structure of build + run: ls -R build + - name: Strip @license from eslint plugin and react-refresh + run: | + sed -i -e 's/ @license React*//' \ + build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ + build/facebook-www/ESLintPluginReactHooks-dev.modern.js \ + build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js + - name: Insert @headers into eslint plugin and react-refresh + run: | + sed -i -e 's/ LICENSE file in the root directory of this source tree./ LICENSE file in the root directory of this source tree.\n *\n * @noformat\n * @nolint\n * @lightSyntaxTransform\n * @preventMunge\n * @oncall react_core/' \ + build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ + build/facebook-www/ESLintPluginReactHooks-dev.modern.js \ + build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js + - name: Move relevant files for React in www into compiled + run: | + # Move the facebook-www folder into compiled + mkdir ./compiled + mv build/facebook-www ./compiled + + # Move ReactAllWarnings.js to facebook-www + mkdir ./compiled/facebook-www/__test_utils__ + mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js + + # Copy eslint-plugin-react-hooks (www build with feature flags) + mkdir ./compiled/eslint-plugin-react-hooks + cp ./compiled/facebook-www/ESLintPluginReactHooks-dev.modern.js \ + ./compiled/eslint-plugin-react-hooks/index.js + + # Move unstable_server-external-runtime.js into facebook-www + mv build/oss-experimental/react-dom/unstable_server-external-runtime.js \ + ./compiled/facebook-www/unstable_server-external-runtime.js + + # Move react-refresh-babel.development.js into babel-plugin-react-refresh + mkdir ./compiled/babel-plugin-react-refresh + mv build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js \ + ./compiled/babel-plugin-react-refresh/index.js + + ls -R ./compiled + - name: Move relevant files for React in fbsource into compiled-rn + run: | + BASE_FOLDER='compiled-rn/facebook-fbsource/xplat/js' + mkdir -p ${BASE_FOLDER}/react-native-github/Libraries/Renderer/ + mkdir -p ${BASE_FOLDER}/RKJSModules/vendor/react/{scheduler,react,react-dom,react-is,react-test-renderer}/ + + # Move React Native renderer + mv build/react-native/implementations/ $BASE_FOLDER/react-native-github/Libraries/Renderer/ + mv build/react-native/shims/ $BASE_FOLDER/react-native-github/Libraries/Renderer/ + mv build/facebook-react-native/scheduler/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/scheduler/ + mv build/facebook-react-native/react/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react/ + mv build/facebook-react-native/react-dom/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-dom/ + mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/ + mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/ + + # Delete the OSS renderers, these are sync'd to RN separately. + RENDERER_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/implementations/ + rm $RENDERER_FOLDER/ReactFabric-{dev,prod,profiling}.js + + # Copy eslint-plugin-react-hooks + # NOTE: This is different from www, here we include the full package + # including package.json to include dependencies in fbsource. + mkdir "$BASE_FOLDER/tools" + cp -r build/oss-experimental/eslint-plugin-react-hooks "$BASE_FOLDER/tools" + + # Move React Native version file + mv build/facebook-react-native/VERSION_NATIVE_FB ./compiled-rn/VERSION_NATIVE_FB + + ls -R ./compiled-rn + - name: Add REVISION files + run: | + echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled/facebook-www/REVISION + cp ./compiled/facebook-www/REVISION ./compiled/facebook-www/REVISION_TRANSFORMS + echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION + - name: "Get current version string" + id: get_current_version + run: | + VERSION_CLASSIC=$(cat ./compiled/facebook-www/VERSION_CLASSIC) + VERSION_MODERN=$(cat ./compiled/facebook-www/VERSION_MODERN) + VERSION_NATIVE_FB=$(cat ./compiled-rn/VERSION_NATIVE_FB) + echo "Current classic version is $VERSION_CLASSIC" + echo "Current modern version is $VERSION_MODERN" + echo "Current rn version is $VERSION_NATIVE_FB" + echo "current_version_classic=$VERSION_CLASSIC" >> "$GITHUB_OUTPUT" + echo "current_version_modern=$VERSION_MODERN" >> "$GITHUB_OUTPUT" + echo "current_version_rn=$VERSION_NATIVE_FB" >> "$GITHUB_OUTPUT" + - uses: actions/upload-artifact@v4 + with: + name: compiled + path: compiled/ + if-no-files-found: error + - uses: actions/upload-artifact@v4 + with: + name: compiled-rn + path: compiled-rn/ + if-no-files-found: error + + commit_www_artifacts: + needs: [download_artifacts, process_artifacts] + if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.www_branch_count == '0') + runs-on: ubuntu-latest + permissions: + # Used to push a commit to builds/facebook-www + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: builds/facebook-www + - name: Ensure clean directory + run: rm -rf compiled + - uses: actions/download-artifact@v4 + with: + name: compiled + path: compiled/ + - name: Revert version changes + if: needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != '' + env: + CURRENT_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.current_version_classic }} + CURRENT_VERSION_MODERN: ${{ needs.process_artifacts.outputs.current_version_modern }} + LAST_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.last_version_classic }} + LAST_VERSION_MODERN: ${{ needs.process_artifacts.outputs.last_version_modern }} + run: | + echo "Reverting $CURRENT_VERSION_CLASSIC to $LAST_VERSION_CLASSIC" + grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled || echo "No files found with $CURRENT_VERSION_CLASSIC" + grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled | xargs -r sed -i -e "s/$CURRENT_VERSION_CLASSIC/$LAST_VERSION_CLASSIC/g" + grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled || echo "Classic version reverted" + echo "====================" + echo "Reverting $CURRENT_VERSION_MODERN to $LAST_VERSION_MODERN" + grep -rl "$CURRENT_VERSION_MODERN" ./compiled || echo "No files found with $CURRENT_VERSION_MODERN" + grep -rl "$CURRENT_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$CURRENT_VERSION_MODERN/$LAST_VERSION_MODERN/g" + grep -rl "$CURRENT_VERSION_MODERN" ./compiled || echo "Modern version reverted" + - name: Check for changes + if: inputs.force != true + id: check_should_commit + run: | + echo "Full git status" + git add . + git status + echo "====================" + if git status --porcelain | grep -qv '/REVISION'; then + echo "Changes detected" + echo "===== Changes =====" + git --no-pager diff -U0 | grep '^[+-]' | head -n 50 + echo "===================" + echo "should_commit=true" >> "$GITHUB_OUTPUT" + else + echo "No Changes detected" + echo "should_commit=false" >> "$GITHUB_OUTPUT" + fi + - name: Re-apply version changes + if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != '') + env: + CURRENT_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.current_version_classic }} + CURRENT_VERSION_MODERN: ${{ needs.process_artifacts.outputs.current_version_modern }} + LAST_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.last_version_classic }} + LAST_VERSION_MODERN: ${{ needs.process_artifacts.outputs.last_version_modern }} + run: | + echo "Re-applying $LAST_VERSION_CLASSIC to $CURRENT_VERSION_CLASSIC" + grep -rl "$LAST_VERSION_CLASSIC" ./compiled || echo "No files found with $LAST_VERSION_CLASSIC" + grep -rl "$LAST_VERSION_CLASSIC" ./compiled | xargs -r sed -i -e "s/$LAST_VERSION_CLASSIC/$CURRENT_VERSION_CLASSIC/g" + grep -rl "$LAST_VERSION_CLASSIC" ./compiled || echo "Classic version re-applied" + echo "====================" + echo "Re-applying $LAST_VERSION_MODERN to $CURRENT_VERSION_MODERN" + grep -rl "$LAST_VERSION_MODERN" ./compiled || echo "No files found with $LAST_VERSION_MODERN" + grep -rl "$LAST_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$LAST_VERSION_MODERN/$CURRENT_VERSION_MODERN/g" + grep -rl "$LAST_VERSION_MODERN" ./compiled || echo "Classic version re-applied" + - name: Will commit these changes + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' + run: | + git add . + git status + - name: Check commit message + if: inputs.dry_run + run: | + git fetch origin --quiet + git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:"%B" + - name: Commit changes to branch + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' + run: | + git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}" + git config --global user.name "${{ github.triggering_actor }}" + + git fetch origin --quiet + git commit -m "$(git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:'%B%n%nDiffTrain build for [${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}](https://github.com/react/react/commit/${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha}})')" || echo "No changes to commit" + - name: Push changes to branch + if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true') + run: git push + + commit_fbsource_artifacts: + needs: [download_artifacts, process_artifacts] + permissions: + # Used to push a commit to builds/facebook-fbsource + contents: write + if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.fbsource_branch_count == '0') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: builds/facebook-fbsource + - name: Ensure clean directory + run: rm -rf compiled-rn + - uses: actions/download-artifact@v4 + with: + name: compiled-rn + path: compiled-rn/ + - name: Revert version changes + if: needs.process_artifacts.outputs.last_version_rn != '' + env: + CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }} + LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }} + run: | + echo "Reverting $CURRENT_VERSION to $LAST_VERSION" + grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "No files found with $CURRENT_VERSION" + grep -rl "$CURRENT_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$CURRENT_VERSION/$LAST_VERSION/g" + grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "Version reverted" + - name: Check for changes + if: inputs.force != 'true' + id: check_should_commit + run: | + echo "Full git status" + git add . + git --no-pager diff -U0 --cached | grep '^[+-]' | head -n 100 + echo "====================" + # Ignore REVISION or lines removing @generated headers. + if git diff --cached ':(exclude)*REVISION' ':(exclude)*/eslint-plugin-react-hooks/package.json' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" > /dev/null; then + echo "Changes detected" + echo "===== Changes =====" + git --no-pager diff --cached ':(exclude)*REVISION' ':(exclude)*/eslint-plugin-react-hooks/package.json' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" | head -n 50 + echo "===================" + echo "should_commit=true" >> "$GITHUB_OUTPUT" + else + echo "No Changes detected" + echo "should_commit=false" >> "$GITHUB_OUTPUT" + fi + - name: Re-apply version changes + if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.process_artifacts.outputs.last_version_rn != '') + env: + CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }} + LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }} + run: | + echo "Re-applying $LAST_VERSION to $CURRENT_VERSION" + grep -rl "$LAST_VERSION" ./compiled-rn || echo "No files found with $LAST_VERSION" + grep -rl "$LAST_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$LAST_VERSION/$CURRENT_VERSION/g" + grep -rl "$LAST_VERSION" ./compiled-rn || echo "Version re-applied" + - name: Add files for signing + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' + run: | + echo ":" + git add . + - name: Signing files + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' + uses: actions/github-script@v7 + with: + script: | + // TODO: Move this to a script file. + // We currently can't call scripts from the repo because + // at this point in the workflow, we're on the compiled + // artifact branch (so the scripts don't exist). + // We can fix this with a composite action in the main repo. + // This script is duplicated above. + const fs = require('fs'); + const crypto = require('crypto'); + const {execSync} = require('child_process'); + + // TODO: when we move this to a script, we can use this from npm. + // Copy of signedsource since we can't install deps on this branch. + const GENERATED = '@' + 'generated'; + const NEWTOKEN = '<>'; + const PATTERN = new RegExp(`${GENERATED} (?:SignedSource<<([a-f0-9]{32})>>)`); + + const TokenNotFoundError = new Error( + `SignedSource.signFile(...): Cannot sign file without token: ${NEWTOKEN}` + ); + + function hash(data, encoding) { + const md5sum = crypto.createHash('md5'); + md5sum.update(data, encoding); + return md5sum.digest('hex'); + } + + const SignedSource = { + getSigningToken() { + return `${GENERATED} ${NEWTOKEN}`; + }, + isSigned(data) { + return PATTERN.exec(data) != null; + }, + signFile(data) { + if (!data.includes(NEWTOKEN)) { + if (SignedSource.isSigned(data)) { + // Signing a file that was previously signed. + data = data.replace(PATTERN, SignedSource.getSigningToken()); + } else { + throw TokenNotFoundError; + } + } + return data.replace(NEWTOKEN, `SignedSource<<${hash(data, 'utf8')}>>`); + }, + }; + + const directory = './compiled-rn'; + console.log('Signing files in directory:', directory); + try { + const result = execSync(`git status --porcelain ${directory}`, {encoding: 'utf8'}); + console.log(result); + + // Parse the git status output to get file paths! + const files = result.split('\n').filter(file => file.endsWith('.js')); + + if (files.length === 0) { + throw new Error( + 'git status returned no files to sign. this job should not have run.' + ); + } else { + files.forEach(line => { + let file = null; + if (line.startsWith('D ')) { + return; + } else if (line.startsWith('R ')) { + file = line.slice(line.indexOf('->') + 3); + } else { + file = line.slice(3).trim(); + } + if (file) { + console.log(' Signing file:', file); + const originalContents = fs.readFileSync(file, 'utf8'); + const signedContents = SignedSource.signFile( + originalContents + // Need to add the header in, since it's not inserted at build time. + .replace(' */\n', ` * ${SignedSource.getSigningToken()}\n */\n`) + ); + + fs.writeFileSync(file, signedContents, 'utf8'); + } + }); + } + } catch (e) { + process.exitCode = 1; + console.error('Error signing files:', e); + } + - name: Will commit these changes + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' + run: | + git add . + git status + - name: Check commit message + if: inputs.dry_run + run: | + git fetch origin --quiet + git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:"%B" + - name: Commit changes to branch + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' + run: | + git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}" + git config --global user.name "${{ github.triggering_actor }}" + + git fetch origin --quiet + git commit -m "$(git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:'%B%n%nDiffTrain build for [${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}](https://github.com/react/react/commit/${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha}})')" || echo "No changes to commit" + - name: Push changes to branch + if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true') + run: git push diff --git a/.github/workflows/runtime_discord_notify.yml b/.github/workflows/runtime_discord_notify.yml new file mode 100644 index 000000000000..22a4b3385dfe --- /dev/null +++ b/.github/workflows/runtime_discord_notify.yml @@ -0,0 +1,51 @@ +name: (Runtime) Discord Notify + +on: + pull_request_target: + types: [opened, ready_for_review] + paths-ignore: + - packages/react-devtools** + - compiler/** + - .github/workflows/compiler_**.yml + - .github/workflows/devtools**.yml + +permissions: {} + +jobs: + check_access: + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-latest + outputs: + is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }} + steps: + - run: echo ${{ github.event.pull_request.author_association }} + - name: Check is member or collaborator + id: check_is_member_or_collaborator + if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }} + run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT" + + check_maintainer: + if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }} + needs: [check_access] + uses: react/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read + with: + actor: ${{ github.event.pull_request.user.login }} + + notify: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + needs: check_maintainer + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.pull_request.user.login }} + embed-author-url: ${{ github.event.pull_request.user.html_url }} + embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }} + embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}' + embed-description: ${{ github.event.pull_request.body }} + embed-url: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/runtime_eslint_plugin_e2e.yml b/.github/workflows/runtime_eslint_plugin_e2e.yml new file mode 100644 index 000000000000..0035d14e6576 --- /dev/null +++ b/.github/workflows/runtime_eslint_plugin_e2e.yml @@ -0,0 +1,62 @@ +name: (Runtime) ESLint Plugin E2E + +on: + push: + branches: [main] + pull_request: + paths-ignore: + - compiler/** + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + # ----- TESTS ----- + test: + name: ESLint v${{ matrix.eslint_major }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + eslint_major: + - "6" + - "7" + - "8" + - "9" + - "10" + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-and-compiler-eslint_e2e-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock', 'fixtures/eslint-v*/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn --cwd compiler install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Install fixture dependencies + working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }} + run: yarn --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Build plugin + working-directory: fixtures/eslint-v${{ matrix.eslint_major }} + run: node build.mjs + - name: Run lint test + working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }} + run: yarn lint diff --git a/.github/workflows/runtime_fuzz_tests.yml b/.github/workflows/runtime_fuzz_tests.yml new file mode 100644 index 000000000000..a88ce523a62f --- /dev/null +++ b/.github/workflows/runtime_fuzz_tests.yml @@ -0,0 +1,33 @@ +name: (Runtime) Fuzz tests + +on: + schedule: + - cron: 0 * * * * + push: + branches: + - main + workflow_dispatch: + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + test_fuzz: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4.1.0 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + - name: Install dependencies + run: yarn install --frozen-lockfile + env: + ELECTRON_SKIP_BINARY_DOWNLOAD: "1" + shell: bash + - name: Run fuzz tests + run: |- + FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci + FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci diff --git a/.github/workflows/runtime_release_from_ci.yml b/.github/workflows/runtime_release_from_ci.yml new file mode 100644 index 000000000000..4ba50d2b5768 --- /dev/null +++ b/.github/workflows/runtime_release_from_ci.yml @@ -0,0 +1,219 @@ +name: (Runtime) Release From CI + +on: + workflow_dispatch: + inputs: + type: + required: true + description: Type of release to publish + type: choice + # The `โ”€โ”€โ”€ ... โ”€โ”€โ”€` entries are visual separators in the dropdown. + # They're rejected by the `resolve` job below, so picking one fails + # the workflow up front instead of silently doing the wrong release. + # GitHub Actions requires choice values to be unique, so the strings + # differ by the number of dashes. + options: + # publishes canary + experimental. + - nightly + - "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + - "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + # semver stable published with @latest. + - stable-latest + - "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + - "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + # semver stable published with @backport (used for patches to + # older release lines that shouldn't move @latest). + - stable-backport + - "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + - "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + # only experimental is published. + - experimental_only + only_packages: + description: Packages to publish (space separated allow-list; empty means all) + type: string + dry: + description: Dry run + type: boolean + default: false + force_notify: + description: Force a Discord notification? + type: boolean + default: false + schedule: + # At 10 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri. + # Scheduled runs always publish a nightly (see `resolve` job). + - cron: 10 16 * * 1,2,3,4,5 + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + resolve: + name: Resolve release inputs + runs-on: ubuntu-latest + outputs: + release_type: ${{ steps.resolve.outputs.release_type }} + steps: + - name: Resolve release inputs + id: resolve + run: | + # Scheduled runs always publish a nightly. Manual dispatches always + # supply `inputs.type`. Anything else is unsupported and fails fast. + if [ "${{ github.event_name }}" = "schedule" ]; then + release_type=nightly + elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + release_type="${{ inputs.type }}" + else + echo "Unsupported event: ${{ github.event_name }}" >&2 + exit 1 + fi + # Reject the dropdown's separator entries (and anything else that + # isn't one of the four real release types). Without this, picking + # a separator would fall through to all of publish.js's `if:` gates + # being false and the job would succeed without doing anything. + case "$release_type" in + nightly|stable-latest|stable-backport|experimental_only) ;; + *) + echo "Invalid release type: '$release_type' โ€” pick one of nightly, stable-latest, stable-backport, experimental_only." >&2 + exit 1 + ;; + esac + echo "release_type=$release_type" >> "$GITHUB_OUTPUT" + + notify_starting: + name: Notify Discord (release starting) + # Manual dispatches always notify before the release starts so the team + # has a heads-up that a release is incoming. Scheduled (nightly) runs + # don't notify up front; we only notify on failure (see `notify` job). + if: ${{ github.event_name == 'workflow_dispatch' && vars.DISABLE_DISCORD_NOTIFICATIONS != 'true' }} + runs-on: ubuntu-latest + steps: + - uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.sender.login }} + embed-author-url: ${{ github.event.sender.html_url }} + embed-author-icon-url: ${{ github.event.sender.avatar_url }} + embed-title: "โš ๏ธ Publishing ${{ inputs.type }} release from source" + embed-description: | + ```json + ${{ toJson(inputs) }} + ``` + embed-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + + publish: + name: Publish release + needs: resolve + if: ${{ !cancelled() && needs.resolve.result == 'success' }} + runs-on: ubuntu-latest + # Protected environment โ€” requires reviewer approval before the publish + # job starts running. + environment: npm + permissions: + id-token: write + contents: read + # `actions: read` lets prepare-release-from-ci.js fetch the + # runtime_build_and_test workflow's artifacts for github.sha. + actions: read + env: + # Required by scripts/release/shared-commands/download-build-artifacts.js. + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + # Always check out the commit the workflow file itself was loaded from. + # Crucially, no user-supplied ref is accepted, since this job runs in a + # protected environment. + - uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} + - uses: actions/setup-node@v4 + with: + # Using modern Node.js that ships with NPM supporting trusted publishing + node-version: "24" + # scripts/release is the only thing this job actually needs to run โ€” + # publish.js and prepare-release-from-ci.js both live there and use its + # own node_modules. Cache is owned by this workflow (this is the only + # consumer), so on a miss we install and save. + - name: Restore cached scripts/release node_modules + uses: actions/cache@v4 + id: release_node_modules + with: + path: scripts/release/node_modules + key: release-scripts-node_modules-v1-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('scripts/release/yarn.lock') }} + - run: yarn --cwd scripts/release install --frozen-lockfile + if: steps.release_node_modules.outputs.cache-hit != 'true' + + # ----- stable (semver) โ€” either @latest or @backport ----- + - name: Stage semver stable artifacts + if: ${{ startsWith(needs.resolve.outputs.release_type, 'stable-') }} + run: scripts/release/prepare-release-from-ci.js --skipTests -r latest --commit=${{ github.sha }} + - name: Publish semver stable to @latest + if: ${{ needs.resolve.outputs.release_type == 'stable-latest' }} + run: | + scripts/release/publish.js \ + --tag=latest \ + ${{ inputs.only_packages && format('--onlyPackages={0}', inputs.only_packages) || '' }} \ + ${{ inputs.dry && '--dry' || '' }} + # Backport releases stay on the `@backport` dist-tag โ€” we don't move + # @latest, and (under OIDC) we can't add/remove dist-tags after publish + # anyway. The tag goes on at publish time and is left in place. + - name: Publish semver stable to @backport + if: ${{ needs.resolve.outputs.release_type == 'stable-backport' }} + run: | + scripts/release/publish.js \ + --tag=backport \ + ${{ inputs.only_packages && format('--onlyPackages={0}', inputs.only_packages) || '' }} \ + ${{ inputs.dry && '--dry' || '' }} + + # ----- nightly: canary first, then experimental ----- + # NOTE: Intentionally running sequentially because npm will sometimes + # fail if you try to concurrently publish two different versions of the + # same package, even if they use different dist tags. + - name: Stage canary artifacts + if: ${{ needs.resolve.outputs.release_type == 'nightly' }} + run: scripts/release/prepare-release-from-ci.js --skipTests -r stable --commit=${{ github.sha }} + # Single tag only โ€” OIDC publish tokens can't add additional dist-tags + # after publish, so the historical `canary,next` aliasing is gone. + - name: Publish canary to @canary + if: ${{ needs.resolve.outputs.release_type == 'nightly' }} + run: | + scripts/release/publish.js \ + --tag=canary \ + ${{ inputs.only_packages && format('--onlyPackages={0}', inputs.only_packages) || '' }} \ + ${{ inputs.dry && '--dry' || '' }} + + # ----- experimental (nightly + experimental_only) ----- + - name: Stage experimental artifacts + if: ${{ needs.resolve.outputs.release_type == 'nightly' || needs.resolve.outputs.release_type == 'experimental_only' }} + run: scripts/release/prepare-release-from-ci.js --skipTests -r experimental --commit=${{ github.sha }} + - name: Publish experimental to @experimental + if: ${{ needs.resolve.outputs.release_type == 'nightly' || needs.resolve.outputs.release_type == 'experimental_only' }} + run: | + scripts/release/publish.js \ + --tag=experimental \ + ${{ inputs.only_packages && format('--onlyPackages={0}', inputs.only_packages) || '' }} \ + ${{ inputs.dry && '--dry' || '' }} + + notify: + name: Notify Discord on failure + needs: [resolve, publish] + # Runs for every workflow run (manual + scheduled) and only fires when + # something didn't complete successfully โ€” i.e. an actual failure or a + # cancellation. Successful runs stay silent. + if: ${{ always() && (needs.resolve.result == 'failure' || needs.resolve.result == 'cancelled' || needs.publish.result == 'failure' || needs.publish.result == 'cancelled') && vars.DISABLE_DISCORD_NOTIFICATIONS != 'true' }} + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: "GitHub Actions" + embed-title: "โŒ [Runtime] Release from source failed (${{ needs.resolve.outputs.release_type || inputs.type || 'nightly' }})" + embed-description: | + resolve: `${{ needs.resolve.result }}` + publish: `${{ needs.publish.result }}` + event: `${{ github.event_name }}` + embed-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }} diff --git a/.github/workflows/shared_check_maintainer.yml b/.github/workflows/shared_check_maintainer.yml new file mode 100644 index 000000000000..f6eb9b9a6d12 --- /dev/null +++ b/.github/workflows/shared_check_maintainer.yml @@ -0,0 +1,58 @@ +name: (Shared) Check maintainer + +on: + workflow_call: + inputs: + actor: + required: true + type: string + outputs: + is_core_team: + value: ${{ jobs.check_maintainer.outputs.is_core_team }} + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + check_maintainer: + runs-on: ubuntu-latest + permissions: + # We fetch the contents of the MAINTAINERS file + contents: read + outputs: + is_core_team: ${{ steps.check_if_actor_is_maintainer.outputs.result }} + steps: + - name: Check if actor is maintainer + id: check_if_actor_is_maintainer + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const actor = '${{ inputs.actor }}'; + const res = await github.rest.repos.getContent({ + owner: 'facebook', + repo: 'react', + path: 'MAINTAINERS', + ref: 'main', + headers: { Accept: 'application/vnd.github+json' } + }); + if (res.status !== 200) { + console.error(res); + throw new Error('Unable to fetch MAINTAINERS file'); + } + content = Buffer.from(res.data.content, 'base64').toString(); + if (content == null || typeof content !== 'string') { + throw new Error('Unable to retrieve MAINTAINERS file'); + } + + const maintainers = new Set(content.split('\n')); + if (maintainers.has(actor)) { + console.log(`๐ŸŸข ${actor} is a maintainer`); + return true; + } + console.log(`๐Ÿ”ด ${actor} is NOT a maintainer`); + return null; diff --git a/.github/workflows/shared_cleanup_merged_branch_caches.yml b/.github/workflows/shared_cleanup_merged_branch_caches.yml new file mode 100644 index 000000000000..ed80a505e428 --- /dev/null +++ b/.github/workflows/shared_cleanup_merged_branch_caches.yml @@ -0,0 +1,41 @@ +# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy + +name: (Shared) Cleanup Merged Branch Caches +on: + pull_request: + types: + - closed + workflow_dispatch: + inputs: + pr_number: + required: true + type: string + +permissions: {} + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: Cleanup + run: | + echo "Fetching list of cache key" + cacheKeysForPR=$(gh cache list --ref $BRANCH --limit 100 --json id --jq '.[].id') + + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cacheKeysForPR + do + gh cache delete $cacheKey + echo "Deleting $cacheKey" + done + echo "Done" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + BRANCH: refs/pull/${{ inputs.pr_number || github.event.pull_request.number }}/merge diff --git a/.github/workflows/shared_cleanup_stale_branch_caches.yml b/.github/workflows/shared_cleanup_stale_branch_caches.yml new file mode 100644 index 000000000000..f6c532b485a4 --- /dev/null +++ b/.github/workflows/shared_cleanup_stale_branch_caches.yml @@ -0,0 +1,36 @@ +# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy + +name: (Shared) Cleanup Stale Branch Caches +on: + schedule: + # Every 6 hours + - cron: 0 */6 * * * + workflow_dispatch: + +permissions: {} + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: Cleanup + run: | + echo "Fetching list of cache keys" + cacheKeysForPR=$(gh cache list --limit 100 --json id,ref --jq '.[] | select(.ref != "refs/heads/main") | .id') + + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cacheKeysForPR + do + gh cache delete $cacheKey + echo "Deleting $cacheKey" + done + echo "Done" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} diff --git a/.github/workflows/shared_close_direct_sync_branch_prs.yml b/.github/workflows/shared_close_direct_sync_branch_prs.yml new file mode 100644 index 000000000000..caa4da880b5f --- /dev/null +++ b/.github/workflows/shared_close_direct_sync_branch_prs.yml @@ -0,0 +1,43 @@ +name: (Shared) Close Direct Sync Branch PRs + +on: + pull_request: + branches: + - 'builds/facebook-**' + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + close_pr: + runs-on: ubuntu-latest + permissions: + # Used to create a review and close PRs + pull-requests: write + contents: write + steps: + - name: Close PR + uses: actions/github-script@v7 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const pullNumber = ${{ github.event.number }}; + + await github.rest.pulls.createReview({ + owner, + repo, + pull_number: pullNumber, + body: 'Do not land changes to `${{ github.event.pull_request.base.ref }}`. Please re-open your PR targeting `main` instead.', + event: 'REQUEST_CHANGES' + }); + await github.rest.pulls.update({ + owner, + repo, + pull_number: pullNumber, + state: 'closed' + }); diff --git a/.github/workflows/shared_label_core_team_prs.yml b/.github/workflows/shared_label_core_team_prs.yml new file mode 100644 index 000000000000..b98a5ca9b20a --- /dev/null +++ b/.github/workflows/shared_label_core_team_prs.yml @@ -0,0 +1,55 @@ +name: (Shared) Label Core Team PRs + +on: + pull_request_target: + types: [opened] + +permissions: {} + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + check_access: + runs-on: ubuntu-latest + outputs: + is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }} + steps: + - run: echo ${{ github.event.pull_request.author_association }} + - name: Check is member or collaborator + id: check_is_member_or_collaborator + if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }} + run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT" + + check_maintainer: + if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }} + needs: [check_access] + uses: react/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read + with: + actor: ${{ github.event.pull_request.user.login }} + + label: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + runs-on: ubuntu-latest + needs: check_maintainer + permissions: + # Used to add labels on issues + issues: write + # Used to add labels on PRs + pull-requests: write + steps: + - name: Label PR as React Core Team + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ github.event.number }}, + labels: ['React Core Team'] + }); diff --git a/.github/workflows/shared_lint.yml b/.github/workflows/shared_lint.yml new file mode 100644 index 000000000000..cd378b1f58bb --- /dev/null +++ b/.github/workflows/shared_lint.yml @@ -0,0 +1,102 @@ +name: (Shared) Lint + +on: + push: + branches: [main] + pull_request: + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + prettier: + name: Run prettier + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: yarn prettier-check + + eslint: + name: Run eslint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Restore cached node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: node ./scripts/tasks/eslint + + check_license: + name: Check license + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: ./scripts/ci/check_license.sh + + test_print_warnings: + name: Test print warnings + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Cache node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - run: ./scripts/ci/test_print_warnings.sh diff --git a/.github/workflows/shared_stale.yml b/.github/workflows/shared_stale.yml new file mode 100644 index 000000000000..c24895edc5da --- /dev/null +++ b/.github/workflows/shared_stale.yml @@ -0,0 +1,55 @@ +# Configuration for stale action workflow - https://github.com/actions/stale +name: (Shared) Manage stale issues and PRs +on: + schedule: + # Run hourly + - cron: '0 * * * *' + workflow_dispatch: + +permissions: + # https://github.com/actions/stale/tree/v9/?tab=readme-ov-file#recommended-permissions + issues: write + pull-requests: write + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + # --- Issues & PRs --- + # Number of days of inactivity before an issue or PR becomes stale + days-before-stale: 90 + # Number of days of inactivity before a stale issue or PR is closed + days-before-close: 7 + # API calls per run + operations-per-run: 100 + + # --- Issues --- + stale-issue-label: "Resolution: Stale" + # Comment to post when marking an issue as stale + stale-issue-message: > + This issue has been automatically marked as stale. + **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. + We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! + # Comment to post when closing a stale issue + close-issue-message: > + Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you! + # Issues with these labels will never be considered stale + exempt-issue-labels: "Partner,React Core Team,Resolution: Backlog,Type: Bug,Type: Discussion,Type: Needs Investigation,Type: Regression,Type: Feature Request,Type: Enhancement" + + # --- PRs --- + stale-pr-label: "Resolution: Stale" + # Comment to post when marking a pull request as stale + stale-pr-message: > + This pull request has been automatically marked as stale. + **If this pull request is still relevant, please leave any comment** (for example, "bump"), and we'll keep it open. + We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated. + # Comment to post when closing a stale pull request + close-pr-message: > + Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you! + # PRs with these labels will never be considered stale + exempt-pr-labels: "Partner,React Core Team,Resolution: Backlog,Type: Bug,Type: Discussion,Type: Needs Investigation,Type: Regression,Type: Feature Request,Type: Enhancement" diff --git a/.gitignore b/.gitignore index 5a913ac6e527..9f0da5163e69 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,13 @@ chrome-user-data .idea *.iml .vscode +.zed *.swp *.swo +/tmp +/.worktrees +.claude/*.local.* +.claude/worktrees packages/react-devtools-core/dist packages/react-devtools-extensions/chrome/build @@ -33,6 +38,7 @@ packages/react-devtools-extensions/firefox/*.xpi packages/react-devtools-extensions/firefox/*.pem packages/react-devtools-extensions/shared/build packages/react-devtools-extensions/.tempUserDataDir +packages/react-devtools-fusebox/dist packages/react-devtools-inline/dist packages/react-devtools-shell/dist -packages/react-devtools-scheduling-profiler/dist \ No newline at end of file +packages/react-devtools-cdt-mcp/dist diff --git a/.mailmap b/.mailmap index 6b3389a7b3ee..e661c3707d5d 100644 --- a/.mailmap +++ b/.mailmap @@ -147,6 +147,7 @@ Steven Luscher Steven Luscher Steven Luscher Steven Luscher +Seth Webster Stoyan Stefanov Tengfei Guo Thomas Aylott diff --git a/.nvmrc b/.nvmrc index 2d3beb1d0214..5f53e875de68 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v12.16.2 +v20.19.0 diff --git a/.prettierignore b/.prettierignore index 80650567efce..2d63a8c6c88d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,8 +1,45 @@ +# react runtime +build + packages/react-devtools-core/dist packages/react-devtools-extensions/chrome/build packages/react-devtools-extensions/firefox/build +packages/react-devtools-extensions/edge/build packages/react-devtools-extensions/shared/build +packages/react-devtools-extensions/src/ErrorTesterCompiled.js +packages/react-devtools-fusebox/dist packages/react-devtools-inline/dist +packages/react-devtools-shared/src/hooks/__tests__/__source__/__compiled__/ +packages/react-devtools-shared/src/hooks/__tests__/__source__/__untransformed__/ packages/react-devtools-shell/dist -packages/react-devtools-scheduling-profiler/dist -packages/react-devtools-scheduling-profiler/static \ No newline at end of file + +# react compiler +compiler/**/dist +compiler/**/__tests__/fixtures/**/*.expect.md +compiler/**/.next + +# contains invalid graphql`...` which results in a promise rejection error from `yarn prettier-all`. +compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.js +# contains invalid const reassignment; the fixture asserts the compiler diagnostic. +compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-reassign-const.js +# preserves the exact sequence-expression source shape used by the fixture. +compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/memoize-value-block-value-sequence.js +# preserves minimized production input; formatting changes the reduced repro shape. +compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo-round3_promote_used_temps.js + +compiler/crates +compiler/target +compiler/apps/playground/public + +compiler/**/LICENSE +compiler/*.md* +compiler/*.json +compiler/*.css +compiler/*.webmanifest +compiler/*.map +compiler/*.sh +compiler/*.txt +compiler/*.ico +compiler/*.svg +compiler/*.lock +compiler/*.toml diff --git a/.prettierrc.js b/.prettierrc.js index 6e5dcb710f0f..d47168603e32 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -5,17 +5,42 @@ const {esNextPaths} = require('./scripts/shared/pathsByLanguageVersion'); module.exports = { bracketSpacing: false, singleQuote: true, - jsxBracketSameLine: true, + bracketSameLine: true, trailingComma: 'es5', printWidth: 80, - parser: 'babel', - + plugins: ['prettier-plugin-hermes-parser'], + parser: 'hermes', + arrowParens: 'avoid', overrides: [ + { + files: ['*.code-workspace'], + options: { + parser: 'json-stringify', + }, + }, { files: esNextPaths, options: { trailingComma: 'all', }, }, + { + files: ['*.ts', '*.tsx'], + options: { + trailingComma: 'all', + parser: 'typescript', + }, + }, + { + // Flow `match` syntax fixtures: prettier's built-in Flow parser cannot + // parse the experimental syntax, hermes-parser can. + files: [ + 'compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/match-*', + ], + options: { + parser: 'hermes', + plugins: ['prettier-plugin-hermes-parser'], + }, + }, ], }; diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index f70e33a4226d..000000000000 --- a/AUTHORS +++ /dev/null @@ -1,1131 +0,0 @@ -839 <8398a7@gmail.com> -Aaron Ackerman -Aaron Cannon -Aaron Franks -Aaron Gelter -Abhay Nikam -Abhishek Soni -Adam -Adam Bloomston -Adam Krebs -Adam Mark -Adam Solove -Adam Stankiewicz -Adam Timberlake -Adam Zapletal -Addy Osmani -Adrian Sieber -Aesop Wolf -Ahmad Wali Sidiqi -Alan Plum -Alan Souza -Alan deLevie -Alastair Hole -Alex -Alex -Alex Babkov -Alex Baumgertner -Alex Boatwright -Alex Boyd -Alex Dajani -Alex Jacobs -Alex Katopodis -Alex Lopatin -Alex Mykyta -Alex Pien -Alex Smith -Alex Zelenskiy -Alex Zherdev -Alexander -Alexander -Alexander Shtuchkin -Alexander Solovyov -Alexander Tseung -Alexandre Gaudencio -Alexandre Kirszenberg -Alexey Raspopov -Alexey Shamrin -Ali Taheri Moghaddar -Ali Ukani -Alireza Mostafizi -Almero Steyn -Amanvir Sangha -Amjad Masad -Anastasia A -Andre Giron -Andre Z Sanchez -Andreas Mรถller -Andreas Savvides -Andreas Svensson -Andres Kalle -Andres Suarez -Andrew Clark -Andrew Cobby -Andrew Davey -Andrew Henderson -Andrew Imm -Andrew Kulakov -Andrew Lo -Andrew Poliakov -Andrew Rasmussen -Andrew Rota -Andrew Sokolov -Andrew Zich -Andrey Marchenko -Andrey Okonetchnikov -Andrey Popp <8mayday@gmail.com> -Andrey Safronov -Andy Edwards -Ankeet Maini -Anthony van der Hoorn -Anto Aravinth -Antonio Ruberto -Antti Ahti -Antรณnio Nuno Monteiro -Anuj Tomar -Anuja Ware -AoDev -April Arcus -Areeb Malik -Aria Buckles -Aria Stewart -Arian Faurtosh -Arni Fannar -Arshabh Kumar Agarwal -Artem Nezvigin -Arthur Gunn -Ashish -Austin Wright -Avinash Kondeti -Ayman Osman -B.Orlov -BDav24 -BEAUDRU Manuel -Baraa Hamodi -Bartosz Kaszubowski -Basarat Ali Syed -Battaile Fauber -Beau Smith -Ben Anderson -Ben Berman -Ben Brooks -Ben Foxall -Ben Halpern -Ben Jaffe -Ben Moss -Ben Newman -Ben Ripkens -Benedikt Meurer -Benjamin Keen -Benjamin Leiken -Benjamin Woodruff -Benjy Cui -Benoit Girard -Benton Rochester -Bernard Lin -Bill Blanchard -Bill Fisher -Billy Shih -Blaine Hatab -Blaine Kasten -Bob Eagan -Bob Ralian -Bob Renwick -Bobby -Bogdan Chadkin -Bojan Mihelac -Boris Yankov -Brad Vogel -Bradford -Bradley Spaulding -Brandon Bloom -Brandon Dail -Brandon Tilley -Brenard Cubacub -Brent Vatne -Brian Cooke -Brian Emil Hartz -Brian Holt -Brian Hsu -Brian Kim -Brian Kung -Brian Reavis -Brian Rue -Brian Vaughn -Bruce Harris -Bruno Heridet -Bruno ล kvorc -Bryan Braun -CT Wu -Cam Song -Cam Spiers -Cameron Chamberlain -Cameron Matheson -Carolina Powers -Carter Chung -Cassus Adam Banko -Cat Chen -Cedric Sohrauer -Cesar William Alvarenga -Chad Fawcett -Changsoon Bok -Charles Marsh -Charlie Garcia -Chase Adams -Cheng Lou -Chitharanjan Das -Chris -Chris Bolin -Chris Grovers -Chris Ha -Chris Pearce -Chris Rebert -Chris Sciolla -Christian Alfoni -Christian Oliff -Christian Roman -Christoffer Sawicki -Christoph Pojer -Christophe Hurpeau -Christopher Monsanto -Claudio Brandolino -Clay Allsopp -Clay Miller -Clement Hoang -CodinCat -Cody Reichert -Colin Wren -Connor McSheffrey -Conor Hastings -Constantin Gavrilete -Cory House -Cotton Hou -Craig Akimoto -Cristovao Verstraeten -DQNEO -Dai Nguyen -Damian Nicholson -Damien Pellier -Damien Soulard -Dan Abramov -Dan Fox -Dan Schafer -DanZeuss -Daniel Carlsson -Daniel Cousens -Daniel Friesen -Daniel Gasienica -Daniel Hejl -Daniel Hejl -Daniel Liburd -Daniel Lo Nigro -Daniel Manรฉ -Daniel Miladinov -Daniel Rodgers-Pryor -Daniel Rosenwasser -Daniel Rotter -Daniel Schonfeld -Daniela Borges -Danilo Vitoriano -Danny Ben-David -Danny Hurlburt -Darcy -Daryl Lau -Darรญo Javier Cravero -Dave Galbraith -Dave Lunny -Dave Voyles -David Aurelio -David Baker -David Beitey -David Ed Mellum -David Goldberg -David Granado -David Greenspan -David Hellsing -David Hu -David Khourshid -David Mininger -David Neubauer -David Percy -Dean Shi -Denis Laxalde -Denis Pismenny -Denis Sokolov -Deniss Jacenko -Dennis Johnson -Desmond Brand -Devedse <2350015+devedse@users.noreply.github.com> -Devinsuit -Devon Blandin -Devon Harvey -Dheeraj Kumar -Dhyey Thakore -Diego Muracciole -Dima Beznos -Dimzel Sobolev -Dmitri Zaitsev -Dmitrii Abramov -Dmitriy Kubyshkin -Dmitriy Rozhkov -Dmitry Blues -Dmitry Mazuro -Dmitry Zhuravlev-Nevsky -Domenico Matteo -Dominic Gannaway -Don Abrams -Dongsheng Liu -Duke Pham -Dustan Kasten -Dustin Getz -Dylan Harrington -Dylan Kirby -Edgar (Algebr) -Eduard -Eduardo Garcia -Edvin Erikson -Elaine Fang -Eli White -Enguerran -Eoin Hennessy -Eric Churchill -Eric Clemmons -Eric Douglas -Eric Eastwood -Eric Elliott -Eric Florenzano -Eric Matthys -Eric Nakagawa -Eric O'Connell -Eric Pitcher -Eric Sakmar -Eric Schoffstall -Erik Harper -Erik Hellman -Espen Hovlandsdal -Esteban -Eugene -EugeneGarbuzov -Evan Coonrod -Evan Jacobs -Evan Scott -Evan Vosberg -Fabio M. Costa -Fabrizio Castellarin -Faheel Ahmad -Fatih -Federico Rampazzo -Felipe Oliveira Carvalho -Felix Gnass -Felix Kling -Fernando Alex Helwanger -Fernando Correia -Fernando Montoya -Filip Hoลกko -Filip Spiridonov -Flarnie Marchan -Fokke Zandbergen -Frank Yan -Frankie Bagnardi -Franรงois Chalifour -Franรงois-Xavier Bois -Fraser Haer -Fred Zhao -Freddy Rangel -Fyodor Ivanishchev -G Scott Olson -G. Kay Lee -Gabe Levi -Gabriel Lett Viviani -Gajus Kuizinas -Gant Laborde -Gareth Nicholson -Garmash Nikolay -Garren Smith -Garrett McCullough -Gavin McQuistin -Gaรซtan Renaudeau -Geert Pasteels -Geert-Jan Brits -George A Sisco III -Georgii Dolzhykov -Gert Hengeveld -Giamir Buoncristiani -Gil Chen-Zion -Gilbert -Giorgio Polvara -Giuseppe -Glen Mailer -Grant Timmerman -Greg Hurrell -Greg Palmer -Greg Perkins -Greg Roodt -Gregory -Grgur Grisogono -Griffin Michl -Guangqiang Dong -Guido Bouman -Guilherme Oenning -Guilherme Ruiz -Guillaume Claret -Harry Hull -Harry Marr -Harry Moreno -Harshad Sabne -Hekar Khani -Hendrik Swanepoel -Henrik Nyh -Henry Harris -Henry Wong -Henry Zhu -Hideo Matsumoto -Hikaru Suido -Hiroyuki Wada -Hou Chia -Huang-Wei Chang -Hugo Agbonon -Hugo Jobling -Hyeock Kwon -Hรฉctor Ramos -Hรฉliton Nordt -Ian Obermiller -Ian Sutherland -Ignacio Carbajo -Igor Scekic -Ike Peters -Ilia Pavlenkov -Ilya Gelman -Ilya Shuklin -Ilyรก Belsky -Ingvar Stepanyan -Irae Carvalho -Isaac Salier-Hellendag -Islam Sharabash -Iurii Kucherov -Ivan <15101126742@163.com> -Ivan Kozik -Ivan Krechetov -Ivan Vergiliev -Ivan Zotov -J. Andrew Brassington -J. Renรฉe Beach -JD Isaacks -JJ Weber -JW -Jack -Jack Cross -Jack Ford -Jack Zhang -Jackie Wung -Jackson Huang -Jacob Gable -Jacob Greenleaf -Jacob Lamont -Jae Hun Lee -Jae Hun Ro -Jaeho Lee -Jaime Mingo -Jake Boone -Jake Worth -Jakub Malinowski -James -James Brantly -James Burnett -James Friend -James Ide -James Long -James Pearce -James Seppi -James South -James Wen -Jamie Wong -Jamis Charles -Jamison Dance -Jan Hancic -Jan Kassens -Jan Raasch -Jan Schรคr -Jane Manchun Wong -Jared Forsyth -Jared Fox -Jarrod Mosen -Jason -Jason Bonta -Jason Grlicky -Jason Ly -Jason Miller -Jason Quense -Jason Trill -Jason Webster -Jay Jaeho Lee -Jay Phelps -Jayen Ashar -Jean Lauliac -Jed Watson -Jeff Barczewski -Jeff Carpenter -Jeff Chan -Jeff Hicken -Jeff Kolesky -Jeff Morrison -Jeff Welch -Jeffrey Lin -Jeffrey Wan -Jen Wong -Jeremy Fairbank -Jess Telford -Jesse Skinner -Jignesh Kakadiya -Jim OBrien -Jim Sproch -Jiminikiz -Jimmy Jea -Jing Chen -Jinwoo Oh -Jinxiu Lee -Jirat Ki -Jiyeon Seo -Jody McIntyre -Joe Critchley -Joe Stein -Joel Auterson -Joel Denning -Joel Sequeira -Johan Tinglรถf -Johannes Baiter -Johannes Emerich -Johannes Lumpe -John Heroy -John Longanecker -John Ryan -John Watson -John-David Dalton -Jon Beebe -Jon Bretman -Jon Chester -Jon Hester -Jon Madison -Jon Scott Clark -Jon Tewksbury -Jonas Enlund -Jonas Gebhardt -Jonathan Hsu -Jonathan Persson -Jordan Harband -Jordan Walke -Jorrit Schippers -Joseph Nudell -Joseph Savona -Josh Bassett -Josh Duck -Josh Hunt -Josh Perez -Josh Yudaken -Joshua Evans -Joshua Go -Joshua Goldberg -Joshua Ma -Joรฃo Valente -Juan -Juan Serrano -Julen Ruiz Aizpuru -Julian Viereck -Julien Bordellier -Julio Lopez -Jun Kim -Jun Wu -Juraj Dudak -Justas Brazauskas -Justin -Justin Grant -Justin Jaffray -Justin Robison -Justin Woo -KB -Kale -Kamron Batman -Karl Horky -Karl Mikkelsen -Karpich Dmitry -Karthik Balakrishnan -Karthik Chintapalli -Kateryna -Kaylee Knowles -KeicaM -Keito Uchiyama -Ken Powers -Kenneth Chau -Kent C. Dodds -Kevin Cheng <09chengk@gmail.com> -Kevin Coughlin -Kevin Huang -Kevin Lacker -Kevin Lau -Kevin Lin -Kevin Old -Kevin Robinson -Kevin Suttle -Kewei Jiang -Keyan Zhang -Kier Borromeo -Kiho ยท Cham -KimCoding -Kirk Steven Hansen -Kit Randel -Kite -Kohei TAKATA -Koo Youngmin -Krystian Karczewski -Kunal Mehta -Kurt Furbush -Kurt Ruppel -Kurt Weiberth -Kyle Kelley -Kyle Mathews -Laurence Rowe -Laurent Etiemble -Lee Byron -Lee Jaeyoung -Lee Sanghyeon -Lei -Leland Richardson -Leon Fedotov -Leon Yip -Leonardo YongUk Kim -Levi Buzolic -Levi McCallum -Lewis Blackwood -Liangzhen Zhu -Lily -Linus Unnebรคck -Lipis -Liz -Logan Allen -Lovisa Svallingson -Lucas -Ludovico Fischer -Luigy Leon -Luke Belliveau -Luke Horvat -Lutz Rosema -MICHAEL JACKSON -MIKAMI Yoshiyuki -Maciej Kasprzyk -Maher Beg -Maksim Shastsel -Manas -Marcelo Alves -Marcin K. -Marcin Kwiatkowski -Marcin Mazurek -Marcin Szczepanski -Marcio Puga -Marcos Ojeda -Marcy Sutton -Mariano Desanze -Mario Souto -Marius Skaar Ludvigsen -Marjan -Mark Anderson -Mark Funk -Mark Hintz -Mark IJbema -Mark Murphy -Mark Pedrotti -Mark Penner -Mark Richardson -Mark Rushakoff -Mark Sun -Marks Polakovs -Marlon Landaverde -Marshall Bowers -Marshall Roch -Martin Andert -Martin Hochel -Martin Hujer -Martin Jul -Martin Konicek -Martin Mihaylov -Martin V -Masaki KOBAYASHI -Mateusz Burzyล„ski -Mathieu M-Gosselin -Mathieu Savy -Matias Singers -Matsunoki -Matt Brookes -Matt Dunn-Rankin -Matt Harrison -Matt Huggins -Matt Stow -Matt Zabriskie -Matthew Dapena-Tretter -Matthew Herbst -Matthew Hodgson -Matthew Johnston -Matthew King -Matthew Looi -Matthew Miner -Matthew Shotton -Matthias Le Brun -Matti Nelimarkka -Mattijs Kneppers -Max Donchenko -Max F. Albrecht <1@178.is> -Max Heiber -Max Stoiber -Maxi Ferreira -Maxim Abramchuk -Maxwel D'souza -Merrick Christensen -Mert KahyaoฤŸlu -Michael Chan -Michael Jackson -Michael McDermott -Michael O'Brien -Michael Randers-Pehrson -Michael Ridgway -Michael Sinov -Michael Terry -Michael Warner -Michael Wiencek -Michael Ziwisky -Michal Srb -Michaล‚ Ordon -Michaล‚ Pierzchaล‚a -Michele Bertoli -Michelle Todd -Michiya -Mihai Parparita -Mike D Pilsbury -Mike Groseclose -Mike Nordick -Mikhail Osher -Mikolaj Dadela -Miles Johnson -Miller Medeiros -Minwe LUO -Minwei Xu -Miorel Palii -Mitchel Humpherys -Mitermayer Reis -Moacir Rosa -Mojtaba Dashtinejad -Morhaus -Moshe Kolodny -Mouad Debbar -Murad -Murray M. Moss -Murtaza Haveliwala -NE-SmallTown -Nadeesha Cabral -Naman Goel -Nate -Nate Hunzaker -Nate Lee -Nate Norberg -Nathan Hardy -Nathan Smith -Nathan White -Nee <944316342@qq.com> -Neo -Neri Marschik -NestorTejero -Nguyen Truong Duy -Nicholas Bergson-Shilcock -Nicholas Clawson -Nick Balestra -Nick Fitzgerald -Nick Gavalas -Nick Kasten -Nick Merwin -Nick Presta -Nick Raienko -Nick Thompson -Nick Williams -Nik Nyby -Nikita Lebedev -Niklas Bostrรถm -Nikoloz Buligini -Nima Jahanshahi -Ning Xia -Niole Nelson -Nolan Lawson -Nuno Campos -OJ Kwon -Oiva Eskola -Oleg -Oleksii Markhovskyi -Oliver Zeigermann -Olivier Tassinari -Omid Hezaveh -Oscar Bolmsten -Oskari Mantere -Owen Coutts -Pablo Lacerda de Miranda -Paolo Moretti -Pascal Hartig -Patrick -Patrick Finnigan -Patrick Laughlin -Patrick Stapleton -Paul Benigeri -Paul Harper -Paul Kehrer -Paul Manta -Paul Oโ€™Shannessy -Paul Seiffert -Paul Shen -Pedro Nauck -Pete Hunt -Peter Blazejewicz -Peter Cottle -Peter Jaros -Peter Newnham -Peter Ruibal -Petri Lehtinen -Petri Lievonen -Phil Quinn -Phil Rajchgot -Philip Jackson -Philipp SpieรŸ -Pieter De Baets -Pieter Vanderwerff -Piotr Czajkowski -Piper Chester -Pontus Abrahamsson -Pouja Nikray -Prathamesh Sonpatki -Prayag Verma -Preston Parry -Qin Junwen -RSG -Rachel D. Cartwright -Rafael -Rafael Angeline -Rafal Dittwald -Ragnar รžรณr Valgeirsson -Rahul Gupta -Rainer Oviir -Raito Bezarius -Rajat Sehgal -Rajiv Tirumalareddy -Ram Kaniyur -Randall Randall -Ray -Ray Dai -Raymond Ha -Reed Loden -Remko Tronรงon -Ricardo -Rich Harris -Richard -Richard D. Worth -Richard Feldman -Richard Kho -Richard Littauer -Richard Livesey -Richard Maisano -Richard Roncancio -Richard Wood -Richie Thomas -Rick Beerendonk -Rick Ford -Riley Tomasek -Rob Arnold -Robert Binna -Robert Chang -Robert Haritonov -Robert Kielty -Robert Knight -Robert Martin -Robert Sedovsek -Robin Berjon -Robin Frischmann -Robin Ricard -Roderick Hsiao -Rodrigo Pombo -Rohan Nair -Roman Liutikov -Roman Matusevich -Roman Pominov -Roman Vanesyan -Rui Araรบjo -Russ -Ryan Lahfa -Ryan Seddon -Ryo Shibayama -Sahat Yalkabov -Saif Hakim -Saiichi Hashimoto -Sakina Crocker -Sam Balana -Sam Beveridge -Sam Saccone -Sam Selikoff -Samer Buna -Samuel -Samuel Hapรกk -Samuel Reed -Samuel Scheiderich -Samy Al Zahrani -Sander Spies -Sasha Aickin -Sassan Haradji -Satoshi Nakajima -Scott -Scott Burch -Scott Feeney -Sean Gransee -Sean Kinsey -Sean Smith -Seba -Sebastian Markbรฅge -Sebastian McKenzie -Senin Roman -Seoh Char -Sercan Eraslan -Serg -Sergey Generalov -Sergey Rubanov -Seyi Adebajo -Shane O'Sullivan -Shaun Trennery -ShihChi Huang -Shim Won -Shinnosuke Watanabe -Shogun Sea -Shota Kubota -Shripad K -Shubheksha Jalan -Shuhei Kagawa -Sibi -Simen Bekkhus -Simon Hรธjberg -Simon Welsh -Simone Vittori -Skasi -Snowmanzzz(Zhengzhong Zhao) -Soichiro Kawamura -Soo Jae Hwang -Sophia -Sophia Westwood -Sophie Alpert -Sota Ohara -Spen Taylor -Spencer Ahrens -Spencer Handley -Sriram Thiagarajan -Stefan Dombrowski -Stephen John Sorensen -Stephen Murphy -Stephie -Sterling Cobb -Steve Baker <_steve_@outlook.com> -Steve Mao -Steven Luscher -Steven Syrek -Steven Vachon -Stolenkid -Stoyan Stefanov -Stuart Harris -SunHuawei -Sundeep Malladi -Sung Won Cho -Sunny Juneja -Sunny Ripert -Superlaziness -Sven Helmberger -Sverre Johansen -Swaroop SM -Sรฉbastien Lorber -Sล‚awomir Laskowski -Taegon Kim -Taeho Kim -Taehwan, No -Tanase Hagi -Tanner -Tay Yang Shun -Ted Kim -TedPowers -Tengfei Guo -Teodor Szente -Tetsuharu OHZEKI -Tetsuya Hasegawa -Thibaut Rizzi -Thomas Aylott -Thomas Boyt -Thomas Broadley -Thomas Reggi -Thomas Rรถggla -Thomas Shaddox -Thomas Shafer -ThomasCrvsr -Tiago Fernandez -Tienchai Wirojsaksaree -Tim Routowicz -Tim Schaub -Timothy Yung -Timur Carpeev -Tobias Reiss -Tom Duncalf -Tom Gasson -Tom Haggie -Tom Hauburger -Tom MacWright -Tom Occhino -Tomasz Koล‚odziejski -Tomoya Suzuki -Tomรกลก Hromada -Tony Rossi -Tony Spiro -Toru Kobayashi -Trevor Smith -Trinh Hoang Nhu -Troy DeMonbreun -Tsung Hung -Tyler Brock -Tyler Buchea -Tyler Deitz -Ujjwal Ojha -Uladzimir Havenchyk -Usman -Ustin Zarubin -Vadim Chernysh -Valentin Shergin -Van der Auwermeulen Grรฉgoire -Varayut Lerdkanlayanawat -Varun Bhuvanendran -Varun Rau -Vasiliy Loginevskiy -Vedat Mahir YILMAZ -Veljko Tornjanski -Vesa Laakso -Victor Alvarez -Victor Homyakov -Victor Koenders -Victoria Quirante -Vikash Agrawal -Ville Immonen -Vincent Riemer -Vincent Siao -Vincent Taing -Vipul A M -Vitaliy Potapov -Vitaly Kramskikh -Vitor Balocco -Vjeux -Vladimir Kovpak -Vladimir Tikunov -Volkan Unsal -Wander Wang -Wayne Larsen -Weizenlol -Whien -WickyNilliams -Will Myers -William Hoffmann -Wincent Colaiuta -Wout Mertens -Xavier Morel -XuefengWu -Yakov Dalinchuk -Yan Li -Yasar icli -Yaxian -YouBao Nong -Yuichi Hagio -Yura Chuchola -Yuriy Dybskiy -Yusong Liu -Yutaka Nakajima -Yuval Dekel -Zac Braddy -Zac Smith -Zach Bruggeman -Zach Ramaekers -Zacharias -Zeke Sikelianos -Zhangjd -adraeth -ankitml -arush -bel3atar -brafdlog -brillout -chen -chocolateboy -cjshawMIT -clariroid -claudiopro -cloudy1 -comerc -cutbko -davidxi -dfrownfelter -djskinner -dongmeng.ldm -everdimension -gillchristian -gitanupam -guoyong yi <451417726@qq.com> -hanumanthan -hao.huang -hjmoss -hkal -iamchenxin -iamdoron -iawia002 -imagentleman -imjanghyuk -inkinworld -jaaberg -jddxf <740531372@qq.com> -jinmmd -koh-taka -kohashi85 -ksvitkovsky -laiso -lamo2k123 -leeyoungalias -li.li -lucas -maxprafferty -mdogadailo -mfijas -mguidotto -mondaychen -najisawas -neeldeep -newvlad -nhducit -ogom -pingan1927 -rgarifullin -saiyagg -scloudyy -segmentationfaulter -shifengchen -songawee -starkch -sugarshin -tokikuch -ventuno -wacii -wali-s -walrusfruitcake -yiminghe -youmoo -yuntao.qyt -z.ky -zhangjg -zhangs -zombieJ -zwhitchcox -รrni Hermann Reynisson -ๅ…ƒๅฝฆ -ๅ‡Œๆ’ -ๅผ ๆ• -็Ž‹ๆ™“ๅ‹‡ -้พ™ๆตท็‡• <1250766229@qq.com> diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a3c50fa6f83..dcd4c5081e55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,863 @@ +## 19.2.7 (June 1, 2026) + +### React Server Components + +- Fixed missing `FormData` entries in Server Actions which regressed in 19.2.6 (@unstubbable [#36566](https://github.com/facebook/react/pull/36566)) + +## 19.2.6 (May 6, 2026) + +### React Server Components + +- Type hardening and performance improvements (@eps1lon, @unstubbable [#36425](https://github.com/facebook/react/pull/36425)) + +## 19.2.5 (March 18, 2026) + +### React Server Components + +- Add more cycle protections (@eps1lon, @unstubbable [#36236](https://github.com/facebook/react/pull/36236)) + +## 19.2.4 (Jan 26, 2026) + +### React Server Components + +- Add more DoS mitigations to Server Actions, and harden Server Components (@gnoff, @lubieowoce, @sebmarkbage, @unstubbable [#35632](https://github.com/facebook/react/pull/35632)) + +## 19.2.3 (Dec 11, 2025) + +### React Server Components + +- Add extra loop protection to React Server Functions (@sebmarkbage [#35351](https://github.com/facebook/react/pull/35351)) + +## 19.2.2 (Dec 11, 2025) + +### React Server Components + +- Move `react-server-dom-webpack/*.unbundled` to private `react-server-dom-unbundled` (@eps1lon [#35290](https://github.com/facebook/react/pull/35290)) +- Patch Promise cycles and toString on Server Functions (@sebmarkbage, @unstubbable [#35289](https://github.com/facebook/react/pull/35289), [#35345](https://github.com/facebook/react/pull/35345)) + +## 19.2.1 (Dec 3, 2025) + +### React Server Components + +- Bring React Server Component fixes to Server Actions (@sebmarkbage [#35277](https://github.com/facebook/react/pull/35277)) + +## 19.2.0 (October 1st, 2025) + +Below is a list of all new features, APIs, and bug fixes. + +Read the [React 19.2 release post](https://react.dev/blog/2025/10/01/react-19-2) for more information. + +### New React Features + +- [``](https://react.dev/reference/react/Activity): A new API to hide and restore the UI and internal state of its children. +- [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent) is a React Hook that lets you extract non-reactive logic into an [Effect Event](https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event). +- [`cacheSignal`](https://react.dev/reference/react/cacheSignal) (for RSCs) lets your know when the `cache()` lifetime is over. +- [React Performance tracks](https://react.dev/reference/dev-tools/react-performance-tracks) appear on the Performance panelโ€™s timeline in your browser developer tools + +### New React DOM Features + +- Added resume APIs for partial pre-rendering with Web Streams: + - [`resume`](https://react.dev/reference/react-dom/server/resume): to resume a prerender to a stream. + - [`resumeAndPrerender`](https://react.dev/reference/react-dom/static/resumeAndPrerender): to resume a prerender to HTML. +- Added resume APIs for partial pre-rendering with Node Streams: + - [`resumeToPipeableStream`](https://react.dev/reference/react-dom/server/resumeToPipeableStream): to resume a prerender to a stream. + - [`resumeAndPrerenderToNodeStream`](https://react.dev/reference/react-dom/static/resumeAndPrerenderToNodeStream): to resume a prerender to HTML. +- Updated [`prerender`](https://react.dev/reference/react-dom/static/prerender) APIs to return a `postponed` state that can be passed to the `resume` APIs. + +### Notable changes + +- React DOM now batches suspense boundary reveals, matching the behavior of client side rendering. This change is especially noticeable when animating the reveal of Suspense boundaries e.g. with the upcoming `` Component. React will batch as much reveals as possible before the first paint while trying to hit popular first-contentful paint metrics. +- Add Node Web Streams (`prerender`, `renderToReadableStream`) to server-side-rendering APIs for Node.js +- Use underscore instead of `:` IDs generated by useId + +### All Changes + +#### React + +- `` was developed over many years, starting before `ClassComponent.setState` (@acdlite @sebmarkbage and many others) +- Stringify context as "SomeContext" instead of "SomeContext.Provider" (@kassens [#33507](https://github.com/facebook/react/pull/33507)) +- Include stack of cause of React instrumentation errors with `%o` placeholder (@eps1lon [#34198](https://github.com/facebook/react/pull/34198)) +- Fix infinite `useDeferredValue` loop in popstate event (@acdlite [#32821](https://github.com/facebook/react/pull/32821)) +- Fix a bug when an initial value was passed to `useDeferredValue` (@acdlite [#34376](https://github.com/facebook/react/pull/34376)) +- Fix a crash when submitting forms with Client Actions (@sebmarkbage [#33055](https://github.com/facebook/react/pull/33055)) +- Hide/unhide the content of dehydrated suspense boundaries if they resuspend (@sebmarkbage [#32900](https://github.com/facebook/react/pull/32900)) +- Avoid stack overflow on wide trees during Hot Reload (@sophiebits [#34145](https://github.com/facebook/react/pull/34145)) +- Improve Owner and Component stacks in various places (@sebmarkbage, @eps1lon: [#33629](https://github.com/facebook/react/pull/33629), [#33724](https://github.com/facebook/react/pull/33724), [#32735](https://github.com/facebook/react/pull/32735), [#33723](https://github.com/facebook/react/pull/33723)) +- Add `cacheSignal` (@sebmarkbage [#33557](https://github.com/facebook/react/pull/33557)) + +#### React DOM + +- Block on Suspensey Fonts during reveal of server-side-rendered content (@sebmarkbage [#33342](https://github.com/facebook/react/pull/33342)) +- Use underscore instead of `:` for IDs generated by `useId` (@sebmarkbage, @eps1lon: [#32001](https://github.com/facebook/react/pull/32001), [https://github.com/facebook/react/pull/33342](https://github.com/facebook/react/pull/33342)[#33099](https://github.com/facebook/react/pull/33099), [#33422](https://github.com/facebook/react/pull/33422)) +- Stop warning when ARIA 1.3 attributes are used (@Abdul-Omira [#34264](https://github.com/facebook/react/pull/34264)) +- Allow `nonce` to be used on hoistable styles (@Andarist [#32461](https://github.com/facebook/react/pull/32461)) +- Warn for using a React owned node as a Container if it also has text content (@sebmarkbage [#32774](https://github.com/facebook/react/pull/32774)) +- s/HTML/text for for error messages if text hydration mismatches (@rickhanlonii [#32763](https://github.com/facebook/react/pull/32763)) +- Fix a bug with `React.use` inside `React.lazy`\-ed Component (@hi-ogawa [#33941](https://github.com/facebook/react/pull/33941)) +- Enable the `progressiveChunkSize` option for server-side-rendering APIs (@sebmarkbage [#33027](https://github.com/facebook/react/pull/33027)) +- Fix a bug with deeply nested Suspense inside Suspense fallback when server-side-rendering (@gnoff [#33467](https://github.com/facebook/react/pull/33467)) +- Avoid hanging when suspending after aborting while rendering (@gnoff [#34192](https://github.com/facebook/react/pull/34192)) +- Add Node Web Streams to server-side-rendering APIs for Node.js (@sebmarkbage [#33475](https://github.com/facebook/react/pull/33475)) + +#### React Server Components + +- Preload `` and `` using hints before they're rendered (@sebmarkbage [#34604](https://github.com/facebook/react/pull/34604)) +- Log error if production elements are rendered during development (@eps1lon [#34189](https://github.com/facebook/react/pull/34189)) +- Fix a bug when returning a Temporary reference (e.g. a Client Reference) from Server Functions (@sebmarkbage [#34084](https://github.com/facebook/react/pull/34084), @denk0403 [#33761](https://github.com/facebook/react/pull/33761)) +- Pass line/column to `filterStackFrame` (@eps1lon [#33707](https://github.com/facebook/react/pull/33707)) +- Support Async Modules in Turbopack Server References (@lubieowoce [#34531](https://github.com/facebook/react/pull/34531)) +- Add support for .mjs file extension in Webpack (@jennyscript [#33028](https://github.com/facebook/react/pull/33028)) +- Fix a wrong missing key warning (@unstubbable [#34350](https://github.com/facebook/react/pull/34350)) +- Make console log resolve in predictable order (@sebmarkbage [#33665](https://github.com/facebook/react/pull/33665)) + +#### React Reconciler + +- [createContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L255-L261) and [createHydrationContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L305-L312) had their parameter order adjusted after `on*` handlers to account for upcoming experimental APIs + +## 19.1.8 (June 1, 2026) + +### React Server Components + +- Fixed missing `FormData` entries in Server Actions which regressed in 19.1.7 (@unstubbable [#36567](https://github.com/facebook/react/pull/36567)) + +## 19.1.7 (May 6, 2026) + +### React Server Components + +- Type hardening and performance improvements (@eps1lon, @unstubbable [#36425](https://github.com/facebook/react/pull/36425)) + +## 19.1.6 (March 18, 2026) + +### React Server Components + +- Add more cycle protections (@eps1lon, @unstubbable [#36236](https://github.com/facebook/react/pull/36236)) + +## 19.1.5 (Jan 26, 2026) + +### React Server Components + +- Add more DoS mitigations to Server Actions, and harden Server Components (@gnoff, @lubieowoce, @sebmarkbage, @unstubbable [#35632](https://github.com/facebook/react/pull/35632)) + +## 19.1.4 (Dec 11, 2025) + +### React Server Components + +- Add extra loop protection to React Server Functions (@sebmarkbage [#35351](https://github.com/facebook/react/pull/35351)) + +## 19.1.3 (Dec 11, 2025) + +### React Server Components + +- Move `react-server-dom-webpack/*.unbundled` to private `react-server-dom-unbundled` (@eps1lon [#35290](https://github.com/facebook/react/pull/35290)) +- Patch Promise cycles and toString on Server Functions (@sebmarkbage, @unstubbable [#35289](https://github.com/facebook/react/pull/35289), [#35345](https://github.com/facebook/react/pull/35345)) + +## 19.1.2 (Dec 3, 2025) + +### React Server Components + +- Bring React Server Component fixes to Server Actions (@sebmarkbage [#35277](https://github.com/facebook/react/pull/35277)) + +## 19.1.1 (July 28, 2025) + +### React +* Fixed Owner Stacks to work with ES2015 function.name semantics ([#33680](https://github.com/facebook/react/pull/33680) by @hoxyq) + +## 19.1.0 (March 28, 2025) + +### Owner Stack + +An Owner Stack is a string representing the components that are directly responsible for rendering a particular component. You can log Owner Stacks when debugging or use Owner Stacks to enhance error overlays or other development tools. Owner Stacks are only available in development builds. Component Stacks in production are unchanged. + +* An Owner Stack is a development-only stack trace that helps identify which components are responsible for rendering a particular component. An Owner Stack is distinct from a Component Stacks, which shows the hierarchy of components leading to an error. +* The [captureOwnerStack API](https://react.dev/reference/react/captureOwnerStack) is only available in development mode and returns a Owner Stack, if available. The API can be used to enhance error overlays or log component relationships when debugging. [#29923](https://github.com/facebook/react/pull/29923), [#32353](https://github.com/facebook/react/pull/32353), [#30306](https://github.com/facebook/react/pull/30306), +[#32538](https://github.com/facebook/react/pull/32538), [#32529](https://github.com/facebook/react/pull/32529), [#32538](https://github.com/facebook/react/pull/32538) + +### React +* Enhanced support for Suspense boundaries to be used anywhere, including the client, server, and during hydration. [#32069](https://github.com/facebook/react/pull/32069), [#32163](https://github.com/facebook/react/pull/32163), [#32224](https://github.com/facebook/react/pull/32224), [#32252](https://github.com/facebook/react/pull/32252) +* Reduced unnecessary client rendering through improved hydration scheduling [#31751](https://github.com/facebook/react/pull/31751) +* Increased priority of client rendered Suspense boundaries [#31776](https://github.com/facebook/react/pull/31776) +* Fixed frozen fallback states by rendering unfinished Suspense boundaries on the client. [#31620](https://github.com/facebook/react/pull/31620) +* Reduced garbage collection pressure by improving Suspense boundary retries. [#31667](https://github.com/facebook/react/pull/31667) +* Fixed erroneous โ€œWaiting for Paintโ€ log when the passive effect phase was not delayed [#31526](https://github.com/facebook/react/pull/31526) +* Fixed a regression causing key warnings for flattened positional children in development mode. [#32117](https://github.com/facebook/react/pull/32117) +* Updated `useId` to use valid CSS selectors, changing format from `:r123:` to `ยซr123ยป`. [#32001](https://github.com/facebook/react/pull/32001) +* Added a dev-only warning for null/undefined created in useEffect, useInsertionEffect, and useLayoutEffect. [#32355](https://github.com/facebook/react/pull/32355) +* Fixed a bug where dev-only methods were exported in production builds. React.act is no longer available in production builds. [#32200](https://github.com/facebook/react/pull/32200) +* Improved consistency across prod and dev to improve compatibility with Google Closure Compiler and bindings [#31808](https://github.com/facebook/react/pull/31808) +* Improve passive effect scheduling for consistent task yielding. [#31785](https://github.com/facebook/react/pull/31785) +* Fixed asserts in React Native when passChildrenWhenCloningPersistedNodes is enabled for OffscreenComponent rendering. [#32528](https://github.com/facebook/react/pull/32528) +* Fixed component name resolution for Portal [#32640](https://github.com/facebook/react/pull/32640) +* Added support for beforetoggle and toggle events on the dialog element. [#32479](https://github.com/facebook/react/pull/32479) + +### React DOM +* Fixed double warning when the `href` attribute is an empty string [#31783](https://github.com/facebook/react/pull/31783) + * Fixed an edge case where `getHoistableRoot()` didnโ€™t work properly when the container was a Document [#32321](https://github.com/facebook/react/pull/32321) +* Removed support for using HTML comments (e.g. ``) as a DOM container. [#32250](https://github.com/facebook/react/pull/32250) +* Added support for ` + + + + + +
+ + + + +`; + + return html; +} diff --git a/compiler/packages/react-mcp-server/src/types/algolia.ts b/compiler/packages/react-mcp-server/src/types/algolia.ts new file mode 100644 index 000000000000..1921dd3f718f --- /dev/null +++ b/compiler/packages/react-mcp-server/src/types/algolia.ts @@ -0,0 +1,100 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// https://github.com/algolia/docsearch/blob/15ebcba606b281aa0dddc4ccb8feb19d396bf79e/packages/docsearch-react/src/types/DocSearchHit.ts +type ContentType = + | 'content' + | 'lvl0' + | 'lvl1' + | 'lvl2' + | 'lvl3' + | 'lvl4' + | 'lvl5' + | 'lvl6'; + +interface DocSearchHitAttributeHighlightResult { + value: string; + matchLevel: 'full' | 'none' | 'partial'; + matchedWords: string[]; + fullyHighlighted?: boolean; +} + +interface DocSearchHitHighlightResultHierarchy { + lvl0: DocSearchHitAttributeHighlightResult; + lvl1: DocSearchHitAttributeHighlightResult; + lvl2: DocSearchHitAttributeHighlightResult; + lvl3: DocSearchHitAttributeHighlightResult; + lvl4: DocSearchHitAttributeHighlightResult; + lvl5: DocSearchHitAttributeHighlightResult; + lvl6: DocSearchHitAttributeHighlightResult; +} + +interface DocSearchHitHighlightResult { + content: DocSearchHitAttributeHighlightResult; + hierarchy: DocSearchHitHighlightResultHierarchy; + hierarchy_camel: DocSearchHitHighlightResultHierarchy[]; +} + +interface DocSearchHitAttributeSnippetResult { + value: string; + matchLevel: 'full' | 'none' | 'partial'; +} + +interface DocSearchHitSnippetResult { + content: DocSearchHitAttributeSnippetResult; + hierarchy: DocSearchHitHighlightResultHierarchy; + hierarchy_camel: DocSearchHitHighlightResultHierarchy[]; +} + +export declare type DocSearchHit = { + objectID: string; + content: string | null; + url: string; + url_without_anchor: string; + type: ContentType; + anchor: string | null; + hierarchy: { + lvl0: string; + lvl1: string; + lvl2: string | null; + lvl3: string | null; + lvl4: string | null; + lvl5: string | null; + lvl6: string | null; + }; + _highlightResult: DocSearchHitHighlightResult; + _snippetResult: DocSearchHitSnippetResult; + _rankingInfo?: { + promoted: boolean; + nbTypos: number; + firstMatchedWord: number; + proximityDistance?: number; + geoDistance: number; + geoPrecision?: number; + nbExactWords: number; + words: number; + filters: number; + userScore: number; + matchedGeoLocation?: { + lat: number; + lng: number; + distance: number; + }; + }; + _distinctSeqID?: number; + __autocomplete_indexName?: string; + __autocomplete_queryID?: string; + __autocomplete_algoliaCredentials?: { + appId: string; + apiKey: string; + }; + __autocomplete_id?: number; +}; + +export type InternalDocSearchHit = DocSearchHit & { + __docsearch_parent: InternalDocSearchHit | null; +}; diff --git a/compiler/packages/react-mcp-server/src/utils/algolia.ts b/compiler/packages/react-mcp-server/src/utils/algolia.ts new file mode 100644 index 000000000000..cfc08022db94 --- /dev/null +++ b/compiler/packages/react-mcp-server/src/utils/algolia.ts @@ -0,0 +1,119 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {DocSearchHit, InternalDocSearchHit} from '../types/algolia'; +import {liteClient, type Hit, type SearchResponse} from 'algoliasearch/lite'; + +// https://github.com/reactjs/react.dev/blob/55986965fbf69c2584040039c9586a01bd54eba7/src/siteConfig.js#L15-L19 +const ALGOLIA_CONFIG = { + appId: '1FCF9AYYAT', + apiKey: '1b7ad4e1c89e645e351e59d40544eda1', + indexName: 'beta-react', +}; + +export const ALGOLIA_CLIENT = liteClient( + ALGOLIA_CONFIG.appId, + ALGOLIA_CONFIG.apiKey, +); + +export function printHierarchy( + hit: DocSearchHit | InternalDocSearchHit, +): string { + let val = `${hit.hierarchy.lvl0} > ${hit.hierarchy.lvl1}`; + if (hit.hierarchy.lvl2 != null) { + val = val.concat(` > ${hit.hierarchy.lvl2}`); + } + if (hit.hierarchy.lvl3 != null) { + val = val.concat(` > ${hit.hierarchy.lvl3}`); + } + if (hit.hierarchy.lvl4 != null) { + val = val.concat(` > ${hit.hierarchy.lvl4}`); + } + if (hit.hierarchy.lvl5 != null) { + val = val.concat(` > ${hit.hierarchy.lvl5}`); + } + if (hit.hierarchy.lvl6 != null) { + val = val.concat(` > ${hit.hierarchy.lvl6}`); + } + return val; +} + +export async function queryAlgolia( + message: string | Array, +): Promise> { + const {results} = await ALGOLIA_CLIENT.search({ + requests: [ + { + query: Array.isArray(message) ? message.join('\n') : message, + indexName: ALGOLIA_CONFIG.indexName, + attributesToRetrieve: [ + 'hierarchy.lvl0', + 'hierarchy.lvl1', + 'hierarchy.lvl2', + 'hierarchy.lvl3', + 'hierarchy.lvl4', + 'hierarchy.lvl5', + 'hierarchy.lvl6', + 'content', + 'url', + ], + attributesToSnippet: [ + `hierarchy.lvl1:10`, + `hierarchy.lvl2:10`, + `hierarchy.lvl3:10`, + `hierarchy.lvl4:10`, + `hierarchy.lvl5:10`, + `hierarchy.lvl6:10`, + `content:10`, + ], + snippetEllipsisText: 'โ€ฆ', + hitsPerPage: 30, + attributesToHighlight: [ + 'hierarchy.lvl0', + 'hierarchy.lvl1', + 'hierarchy.lvl2', + 'hierarchy.lvl3', + 'hierarchy.lvl4', + 'hierarchy.lvl5', + 'hierarchy.lvl6', + 'content', + ], + }, + ], + }); + const firstResult = results[0] as SearchResponse; + const {hits} = firstResult; + const deduped = new Map(); + for (const hit of hits) { + // drop hashes to dedupe properly + const u = new URL(hit.url); + if (deduped.has(u.pathname)) { + continue; + } + deduped.set(u.pathname, hit); + } + const pages: Array = await Promise.all( + Array.from(deduped.values()).map(hit => { + return fetch(hit.url, { + headers: { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', + }, + }).then(res => { + if (res.ok === true) { + return res.text(); + } else { + console.error( + `Could not fetch docs: ${res.status} ${res.statusText}`, + ); + return null; + } + }); + }), + ); + return pages.filter(page => page !== null); +} diff --git a/compiler/packages/react-mcp-server/src/utils/assertExhaustive.ts b/compiler/packages/react-mcp-server/src/utils/assertExhaustive.ts new file mode 100644 index 000000000000..2adfffa8d7ea --- /dev/null +++ b/compiler/packages/react-mcp-server/src/utils/assertExhaustive.ts @@ -0,0 +1,13 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Trigger an exhaustiveness check in TypeScript and throw at runtime. + */ +export default function assertExhaustive(_: never, errorMsg: string): never { + throw new Error(errorMsg); +} diff --git a/compiler/packages/react-mcp-server/todo.md b/compiler/packages/react-mcp-server/todo.md new file mode 100644 index 000000000000..a7f0af9adbee --- /dev/null +++ b/compiler/packages/react-mcp-server/todo.md @@ -0,0 +1,5 @@ +TODO + +- [ ] If code doesnt compile, read diagnostics and try again +- [ ] Provide detailed examples in assistant prompt (use another LLM to generate good prompts, iterate from there) +- [ ] Provide more tools for working with HIR/AST (eg so we can prompt it to try and optimize code via HIR, which it can then translate back into user code changes) diff --git a/compiler/packages/react-mcp-server/tsconfig.json b/compiler/packages/react-mcp-server/tsconfig.json new file mode 100644 index 000000000000..0de3a4a61511 --- /dev/null +++ b/compiler/packages/react-mcp-server/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "@tsconfig/strictest/tsconfig.json", + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16", + "rootDir": "../", + "noEmit": true, + "jsx": "react-jsxdev", + "lib": ["ES2022"], + + // weaken strictness from preset + "importsNotUsedAsValues": "remove", + "noUncheckedIndexedAccess": false, + "noUnusedParameters": false, + "useUnknownInCatchVariables": false, + "target": "ES2022", + // ideally turn off only during dev, or on a per-file basis + "noUnusedLocals": false, + }, + "exclude": ["node_modules"], + "include": ["src/**/*.ts"], +} diff --git a/compiler/packages/react-mcp-server/tsup.config.ts b/compiler/packages/react-mcp-server/tsup.config.ts new file mode 100644 index 000000000000..820410e20f65 --- /dev/null +++ b/compiler/packages/react-mcp-server/tsup.config.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {defineConfig} from 'tsup'; + +export default defineConfig({ + entry: ['./src/index.ts'], + outDir: './dist', + external: [], + splitting: false, + sourcemap: false, + dts: false, + bundle: true, + format: 'cjs', + platform: 'node', + target: 'es2022', + banner: { + js: `#!/usr/bin/env node + +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @lightSyntaxTransform + * @noflow + * @nolint + * @preventMunge + * @preserve-invariant-messages + */`, + }, +}); diff --git a/compiler/packages/snap/package.json b/compiler/packages/snap/package.json new file mode 100644 index 000000000000..e2edb778167b --- /dev/null +++ b/compiler/packages/snap/package.json @@ -0,0 +1,65 @@ +{ + "name": "snap", + "version": "0.0.1", + "public": false, + "description": "Snapshot testing CLI tool", + "main": "dist/main.js", + "license": "MIT", + "files": [ + "src" + ], + "scripts": { + "postinstall": "./scripts/link-react-compiler-runtime.sh && perl -p -i -e 's/react\\.element/react.transitional.element/' ../../node_modules/fbt/lib/FbtReactUtil.js && perl -p -i -e 's/didWarnAboutUsingAct = false;/didWarnAboutUsingAct = true;/' ../../node_modules/react-dom/cjs/react-dom-test-utils.development.js", + "build": "rimraf dist && concurrently -n snap,runtime \"tsc --build\" \"yarn --silent workspace react-compiler-runtime build\"", + "snap": "node dist/main.js", + "test": "echo 'no tests'", + "prettier": "prettier --write 'src/**/*.ts'" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/react/react.git", + "directory": "compiler/packages/snap" + }, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.19.1", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/preset-flow": "^7.7.4", + "@babel/preset-typescript": "^7.26.0", + "@parcel/watcher": "^2.1.0", + "@testing-library/react": "^13.4.0", + "babel-plugin-idx": "^3.0.3", + "babel-plugin-syntax-hermes-parser": "^0.25.1", + "chalk": "4", + "fbt": "^1.0.2", + "glob": "^10.3.10", + "hermes-parser": "^0.32.0", + "jsdom": "^22.1.0", + "react": "0.0.0-experimental-4beb1fd8-20241118", + "react-dom": "0.0.0-experimental-4beb1fd8-20241118", + "readline": "^1.3.0", + "yargs": "^17.7.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "devDependencies": { + "@babel/core": "^7.19.1", + "@babel/parser": "^7.20.15", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@types/babel__code-frame": "^7.0.6", + "@types/fbt": "^1.0.4", + "@types/glob": "^8.1.0", + "@types/node": "^18.7.18", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "object-assign": "^4.1.1" + }, + "resolutions": { + "./**/@babel/parser": "7.7.4", + "./**/@babel/types": "7.7.4", + "@babel/generator": "7.2.0", + "@babel/preset-flow": "7.22.5" + } +} diff --git a/compiler/packages/snap/scripts/link-react-compiler-runtime.sh b/compiler/packages/snap/scripts/link-react-compiler-runtime.sh new file mode 100755 index 000000000000..83a30d41d7c8 --- /dev/null +++ b/compiler/packages/snap/scripts/link-react-compiler-runtime.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +set -eo pipefail + +yarn --silent workspace react-compiler-runtime link +yarn --silent workspace snap link react-compiler-runtime diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts new file mode 100644 index 000000000000..c07f0194d0bf --- /dev/null +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -0,0 +1,525 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const skipFilter = new Set([ + /** + * Fixtures using external modules (jest, Lexical, etc.) that can't be evaluated + * in the test harness. These were previously error.todo-* but now compile in both TS and Rust. + */ + 'todo-hir_identifier_diff', + 'todo-hir_numeric_format', + 'todo-pattern1b_type_to_primitive', + 'todo-round2_unicode_string', + 'todo-round3_outlined_naming', + 'todo-round3_promote_used_temps', + + /** + * `export as namespace` is a .d.ts-shaped construct that breaks sprout's + * second-stage TS->CJS evaluator transform itself. The sibling ts-* interop + * fixtures are deliberately not skipped: that transform handles their + * syntax, so they pass sprout (still producing the standard "Fixture not + * implemented" eval result). + */ + 'ts-namespace-export-declaration', + + /** + * `using`/`await using` (explicit resource management) is not supported by + * the Node version the evaluator runs on. + */ + 'using-declaration-bailout-sibling-compiles', + + /** + * Observable different in logging between Forget and non-Forget + */ + 'early-return-no-declarations-reassignments-dependencies', + + /** + * Category A: + * Tests with 0 parameters and 0 refs to external values + */ + // TODO: fix invalid .set call + 'assignment-variations-complex-lvalue-array', + // TODO: uses jsx (requires React) + 'sketchy-code-rules-of-hooks', + // TODO: fix infinite loop + 'ssa-for-trivial-update', + // TODO: fix infinite loop + 'ssa-while-no-reassign', + + /** + * Category B: + * Tests with at least one param and 0 refs to external values + */ + 'bug.useMemo-deps-array-not-cleared', + 'capture_mutate-across-fns', + 'capture-indirect-mutate-alias', + 'capturing-arrow-function-1', + 'capturing-func-mutate-3', + 'capturing-func-mutate-nested', + 'capturing-function-1', + 'capturing-function-alias-computed-load', + 'capturing-function-decl', + 'capturing-function-skip-computed-path', + 'capturing-function-within-block', + 'capturing-member-expr', + 'capturing-nested-member-call', + 'capturing-nested-member-expr-in-nested-func', + 'capturing-nested-member-expr', + 'capturing-variable-in-nested-block', + 'capturing-variable-in-nested-function', + 'complex-while', + 'component', + 'cond-deps-conditional-member-expr', + 'conditional-break-labeled', + 'propagate-scope-deps-hir-fork/conditional-break-labeled', + 'conditional-set-state-in-render', + 'constant-computed', + 'constant-propagation-phi', + 'debugger-memoized', + 'debugger', + 'declare-reassign-variable-in-closure', + 'delete-computed-property', + 'delete-property', + 'dependencies-outputs', + 'dependencies', + 'destructure-direct-reassignment', + 'destructuring-array-default', + 'destructuring-array-param-default', + 'destructuring-assignment-array-default', + 'destructuring-assignment', + 'destructuring-object-default', + 'destructuring-object-param-default', + 'destructuring', + 'disable-jsx-memoization', + 'do-while-break', + 'do-while-compound-test', + 'dominator', + 'early-return', + 'escape-analysis-destructured-rest-element', + 'escape-analysis-jsx-child', + 'escape-analysis-logical', + 'escape-analysis-non-escaping-interleaved-allocating-dependency', + 'escape-analysis-non-escaping-interleaved-allocating-nested-dependency', + 'escape-analysis-non-escaping-interleaved-primitive-dependency', + 'escape-analysis-not-conditional-test', + 'escape-analysis-not-if-test', + 'escape-analysis-not-switch-case', + 'escape-analysis-not-switch-test', + 'expression-with-assignment-dynamic', + 'extend-scopes-if', + 'fbt/fbt-params', + 'for-empty-update-with-continue', + 'for-empty-update', + 'for-logical', + 'for-return', + 'function-declaration-simple', + 'function-param-assignment-pattern', + 'globals-Boolean', + 'globals-Number', + 'globals-String', + 'holey-array-pattern-dce-2', + 'holey-array-pattern-dce', + 'holey-array', + 'independently-memoize-object-property', + 'inverted-if-else', + 'inverted-if', + 'jsx-empty-expression', + 'jsx-fragment', + 'jsx-namespaced-name', + 'lambda-mutated-non-reactive-to-reactive', + 'lambda-mutated-ref-non-reactive', + 'logical-expression-object', + 'logical-expression', + 'nested-function-shadowed-identifiers', + 'nonoptional-load-from-optional-memberexpr', + 'object-computed-access-assignment', + 'object-expression-string-literal-key', + 'object-literal-spread-element', + 'object-pattern-params', + 'optional-member-expression-chain', + 'overlapping-scopes-interleaved-by-terminal', + 'overlapping-scopes-interleaved', + 'overlapping-scopes-shadowed', + 'overlapping-scopes-shadowing-within-block', + 'overlapping-scopes-while', + 'overlapping-scopes-within-block', + 'prop-capturing-function-1', + 'reactive-scopes-if', + 'reactive-scopes', + 'reactivity-analysis-interleaved-reactivity', + 'reassign-object-in-context', + 'reassignment-separate-scopes', + 'return-conditional', + 'return-undefined', + 'reverse-postorder', + 'same-variable-as-dep-and-redeclare-maybe-frozen', + 'same-variable-as-dep-and-redeclare', + 'simple-scope', + 'ssa-arrayexpression', + 'ssa-for-of', + 'ssa-multiple-phis', + 'ssa-nested-loops-no-reassign', + 'ssa-nested-partial-phi', + 'ssa-nested-partial-reassignment', + 'ssa-non-empty-initializer', + 'ssa-objectexpression', + 'ssa-property-alias-if', + 'ssa-reassign', + 'ssa-renaming-via-destructuring', + 'ssa-renaming', + 'ssa-sibling-phis', + 'switch-with-fallthrough', + 'ternary-assignment-expression', + 'ternary-expression', + 'trivial', + 'type-args-test-binary-operator', + 'type-cast-expression.flow', + 'unary-expr', + 'unconditional-break-label', + 'unused-array-middle-element', + 'unused-array-rest-element', + 'unused-conditional', + 'unused-logical', + 'unused-object-element-with-rest', + 'unused-object-element', + 'useMemo-inlining-block-return', + 'useMemo-inverted-if', + 'useMemo-labeled-statement-unconditional-return', + 'useMemo-logical', + 'useMemo-nested-ifs', + 'useMemo-switch-no-fallthrough', + 'useMemo-switch-return', + 'while-break', + 'while-conditional-continue', + 'while-logical', + 'while-property', + 'validate-no-set-state-in-render-uncalled-function-with-mutable-range-is-valid', + // Category B with multiple entrypoints, + 'conditional-break', + + /** + * Category C: + * Tests with at 0 params and at least one ref to external values + */ + 'alias-capture-in-method-receiver', + 'alias-nested-member-path-mutate', + 'concise-arrow-expr', + 'const-propagation-into-function-expression-global', + 'lambda-mutate-shadowed-object', + 'fbt/lambda-with-fbt', + 'recursive-function-expr', + 'ref-current-aliased-no-added-to-dep', + 'ref-current-field-not-added-to-dep', + 'ref-current-not-added-to-dep', + 'ref-current-optional-field-no-added-to-dep', + 'ref-current-write-not-added-to-dep', + 'rewrite-phis-in-lambda-capture-context', + 'sketchy-code-exhaustive-deps', + 'ssa-property-alias-mutate', + 'ssa-property-mutate-2', + 'ssa-property-mutate-alias', + 'ssa-property-mutate', + 'ssa-reassign-in-rval', + 'store-via-call', + 'store-via-new', + 'tagged-template-literal', + 'transitive-alias-fields', + 'type-binary-operator', + 'type-test-field-load-binary-op', + 'type-test-polymorphic', + 'type-test-return-type-inference', + 'use-callback-simple', + // defines two functions + 'simple-alias', + + /** + * Category D: + * Tests with one or more params, with external references. + */ + 'alias-computed-load', + 'allocating-primitive-as-dep', + 'allow-passing-refs-as-props', + 'array-at-closure', + 'array-at-effect', + 'array-at-mutate-after-capture', + 'array-join', + 'array-push-effect', + 'assignment-in-nested-if', + 'await-side-effecting-promise', + 'await', + 'builtin-jsx-tag-lowered-between-mutations', + 'call-args-assignment', + 'call-args-destructuring-assignment', + 'call-with-independently-memoizable-arg', + 'capture-param-mutate', + 'capturing-function-conditional-capture-mutate', + 'capturing-function-member-expr-arguments', + 'capturing-function-member-expr-call', + 'codegen-emit-imports-same-source', + 'codegen-emit-make-read-only', + 'computed-call-spread', + 'computed-load-primitive-as-dependency', + 'destructuring-mixed-scope-declarations-and-locals', + 'destructuring-property-inference', + 'do-while-conditional-break', + 'do-while-early-unconditional-break', + 'fbt/fbt-params-complex-param-value', + 'function-expression-captures-value-later-frozen-jsx', + 'function-expression-maybe-mutates-hook-return-value', + 'function-expression-with-store-to-parameter', + 'global-jsx-tag-lowered-between-mutations', + 'hook-inside-logical-expression', + 'immutable-hooks', + 'inadvertent-mutability-readonly-class', + 'inadvertent-mutability-readonly-lambda', + 'infer-computed-delete', + 'infer-property-delete', + 'inner-memo-value-not-promoted-to-outer-scope-dynamic', + 'inner-memo-value-not-promoted-to-outer-scope-static', + 'issue852', + 'jsx-member-expression-tag-grouping', + 'jsx-member-expression', + 'jsx-spread', + 'lambda-capture-returned-alias', + 'method-call-computed', + 'method-call-fn-call', + 'nested-optional-member-expr', + 'nested-scopes-hook-call', + 'new-spread', + 'obj-literal-cached-in-if-else', + 'obj-literal-mutated-after-if-else', + 'obj-mutated-after-if-else-with-alias', + 'obj-mutated-after-if-else', + 'obj-mutated-after-nested-if-else-with-alias', + 'object-properties', + 'optional-call-chained', + 'optional-call-logical', + 'optional-call-simple', + 'optional-call-with-independently-memoizable-arg', + 'optional-call-with-optional-property-load', + 'optional-call', + 'optional-computed-load-static', + 'optional-computed-member-expression', + 'optional-member-expression-call-as-property', + 'optional-member-expression-with-optional-member-expr-as-property', + 'optional-member-expression', + 'optional-method-call', + 'optional-receiver-method-call', + 'optional-receiver-optional-method', + 'primitive-alias-mutate', + 'primitive-as-dep', + 'property-assignment', + 'property-call-spread', + 'reactive-dependencies-non-optional-properties-inside-optional-chain', + 'reactivity-analysis-reactive-via-mutation-of-computed-load', + 'reactivity-analysis-reactive-via-mutation-of-property-load', + 'reassigned-phi-in-returned-function-expression', + 'reassignment-conditional', + 'reassignment', + 'ref-current-aliased-not-added-to-dep-2', + 'ref-current-not-added-to-dep-2', + 'ref-in-effect', + 'regexp-literal', + 'remove-memoization-kitchen-sink', + 'repro-reassign-to-variable-without-mutable-range', + 'repro-scope-missing-mutable-range', + 'repro', + 'simple', + 'ssa-property-alias-alias-mutate-if', + 'ssa-property-alias-mutate-if', + 'ssa-property-alias-mutate-inside-if', + 'switch-global-propertyload-case-test', + 'switch-non-final-default', + 'switch', + 'tagged-template-in-hook', + 'temporary-accessed-outside-scope', + 'temporary-at-start-of-value-block', + 'temporary-property-load-accessed-outside-scope', + 'timers', + 'todo-function-expression-captures-value-later-frozen', + 'uninitialized-declaration-in-reactive-scope', + 'unknown-hooks-do-not-assert', + 'unused-logical-assigned-to-variable', + 'unused-optional-method-assigned-to-variable', + 'unused-ternary-assigned-to-variable', + 'useEffect-arg-memoized', + 'useEffect-nested-lambdas', + 'useMemo-if-else-multiple-return', + 'useMemo-independently-memoizeable', + 'useMemo-named-function', + 'useMemo-return-empty', + 'useMemo-simple', + 'use-no-forget-module-level', + 'use-no-memo-module-level', + // defines multiple functions + 'alias-while', + 'babel-existing-react-import', + 'babel-existing-react-kitchensink-import', + 'call', + 'codegen-instrument-forget-test', + 'conditional-on-mutable', + 'constructor', + 'frozen-after-alias', + 'hook-call', + 'hooks-freeze-arguments', + 'hooks-freeze-possibly-mutable-arguments', + 'independent-across-if', + 'independent', + 'interdependent-across-if', + 'interdependent', + 'mutable-liverange-loop', + 'sequence-expression', + 'ssa-call-jsx-2', + 'ssa-call-jsx', + 'ssa-newexpression', + 'ssa-shadowing', + 'template-literal', + + // works, but appears differently when printing + // due to optional function argument + 'nested-function-with-param-as-captured-dep', + 'deeply-nested-function-expressions-with-params', + + // TODO: we should be able to support these + 'readonly-object-method-calls', + 'readonly-object-method-calls-mutable-lambda', + 'preserve-memo-validation/useMemo-with-refs.flow', + + // TODO: we probably want to always skip these + 'rules-of-hooks/rules-of-hooks-0592bd574811', + 'rules-of-hooks/rules-of-hooks-0e2214abc294', + 'rules-of-hooks/rules-of-hooks-1ff6c3fbbc94', + 'rules-of-hooks/rules-of-hooks-23dc7fffde57', + 'rules-of-hooks/rules-of-hooks-2bec02ac982b', + 'rules-of-hooks/rules-of-hooks-2e405c78cb80', + 'rules-of-hooks/rules-of-hooks-33a6e23edac1', + 'rules-of-hooks/rules-of-hooks-347b0dae66f1', + 'rules-of-hooks/rules-of-hooks-485bf041f55f', + 'rules-of-hooks/rules-of-hooks-4f6c78a14bf7', + 'rules-of-hooks/rules-of-hooks-7e52f5eec669', + 'rules-of-hooks/rules-of-hooks-844a496db20b', + 'rules-of-hooks/rules-of-hooks-8f1c2c3f71c9', + 'rules-of-hooks/rules-of-hooks-9a47e97b5d13', + 'rules-of-hooks/rules-of-hooks-9d7879272ff6', + 'rules-of-hooks/rules-of-hooks-c1e8c7f4c191', + 'rules-of-hooks/rules-of-hooks-c5d1f3143c4c', + 'rules-of-hooks/rules-of-hooks-cfdfe5572fc7', + 'rules-of-hooks/rules-of-hooks-df4d750736f3', + 'rules-of-hooks/rules-of-hooks-dfde14171fcd', + 'rules-of-hooks/rules-of-hooks-e5dd6caf4084', + 'rules-of-hooks/rules-of-hooks-e66a744cffbe', + 'rules-of-hooks/rules-of-hooks-eacfcaa6ef89', + 'rules-of-hooks/rules-of-hooks-fe6042f7628b', + 'infer-function-assignment', + 'infer-functions-component-with-jsx', + 'infer-function-forwardRef', + 'infer-function-React-memo', + 'infer-functions-component-with-hook-call', + 'infer-functions-component-with-jsx', + 'infer-functions-hook-with-hook-call', + 'infer-functions-hook-with-jsx', + 'infer-function-expression-component', + 'infer-skip-components-without-hooks-or-jsx', + 'class-component-with-render-helper', + 'fbt/fbtparam-with-jsx-element-content', + 'fbt/fbtparam-text-must-use-expression-container', + 'fbt/fbtparam-with-jsx-fragment-value', + 'todo.useContext-mutate-context-in-callback', + 'loop-unused-let', + 'reanimated-no-memo-arg', + 'reanimated-shared-value-writes', + + 'userspace-use-memo-cache', + 'transitive-freeze-function-expressions', + + // nothing to compile/run + 'gating/repro-no-gating-import-without-compiled-functions', + + // TODOs + 'rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af', + 'rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c', + 'rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b', + 'rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb', + 'rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8', + 'rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e', + 'rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f', + 'rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8', + 'rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3', + 'todo.unnecessary-lambda-memoization', + 'rules-of-hooks/rules-of-hooks-93dc5d5e538a', + 'rules-of-hooks/rules-of-hooks-69521d94fa03', + + // false positives + 'invalid-jsx-lowercase-localvar', + + // bugs + 'inner-function/nullable-objects/bug-invalid-array-map-manual', + 'bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr', + `bug-capturing-func-maybealias-captured-mutate`, + 'bug-aliased-capture-aliased-mutate', + 'bug-aliased-capture-mutate', + 'bug-functiondecl-hoisting', + 'bug-type-inference-control-flow', + 'fbt/bug-fbt-plural-multiple-function-calls', + 'fbt/bug-fbt-plural-multiple-mixed-call-tag', + 'bug-invalid-phi-as-dependency', + 'bug-ref-prefix-postfix-operator', + + // 'react-compiler-runtime' not yet supported + 'flag-enable-emit-hook-guards', + 'fast-refresh-refresh-on-const-changes-dev', + 'useState-pruned-dependency-change-detect', + 'useState-unpruned-dependency', + 'useState-and-other-hook-unpruned-dependency', + 'change-detect-reassign', + + // Depends on external functions + 'idx-method-no-outlining-wildcard', + 'idx-method-no-outlining', + 'target-flag-meta-internal', + + // needs to be executed as a module + 'meta-property', + + // needs context lowering support in React + 'todo.lower-context-access-property-load', + 'todo.lower-context-access-nested-destructuring', + 'todo.lower-context-access-mixed-array-obj', + 'todo.lower-context-access-destructure-multiple', + 'todo.lower-context-access-array-destructuring', + 'lower-context-selector-simple', + 'lower-context-acess-multiple', + 'bug-separate-memoization-due-to-callback-capturing', + + // SSR optimization rewrites files in a way that causes differences or warnings + 'ssr/optimize-ssr', + 'ssr/ssr-use-reducer', + 'ssr/ssr-use-reducer-initializer', + 'ssr/infer-event-handlers-from-setState', + 'ssr/infer-event-handlers-from-startTransition', +]); + +export default skipFilter; diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts new file mode 100644 index 000000000000..e527c58d367b --- /dev/null +++ b/compiler/packages/snap/src/compiler.ts @@ -0,0 +1,401 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type * as BabelCore from '@babel/core'; +import {transformFromAstSync} from '@babel/core'; + +import * as BabelParser from '@babel/parser'; +import {NodePath} from '@babel/traverse'; +import * as t from '@babel/types'; +import type { + Logger, + LoggerEvent, + PluginOptions, + CompilerReactTarget, + CompilerPipelineValue, +} from 'babel-plugin-react-compiler/src/Entrypoint'; +import type { + Effect, + ValueKind, + ValueReason, +} from 'babel-plugin-react-compiler/src/HIR'; +import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/Utils/TestUtils'; +import * as HermesParser from 'hermes-parser'; +import invariant from 'invariant'; +import path from 'path'; +import prettier from 'prettier'; +import SproutTodoFilter from './SproutTodoFilter'; +import {isExpectError} from './fixture-utils'; +import {makeSharedRuntimeTypeProvider} from './sprout/shared-runtime-type-provider'; + +export function parseLanguage(source: string): 'flow' | 'typescript' { + return source.indexOf('@flow') !== -1 ? 'flow' : 'typescript'; +} + +export function parseSourceType(source: string): 'script' | 'module' { + return source.indexOf('@script') !== -1 ? 'script' : 'module'; +} + +/** + * Parse react compiler plugin + environment options from test fixture. Note + * that although this primarily uses `Environment:parseConfigPragma`, it also + * has test fixture specific (i.e. not applicable to playground) parsing logic. + */ +function makePluginOptions( + firstLine: string, + parseConfigPragmaFn: typeof ParseConfigPragma, + debugIRLogger: (value: CompilerPipelineValue) => void, + EffectEnum: typeof Effect, + ValueKindEnum: typeof ValueKind, + ValueReasonEnum: typeof ValueReason, +): { + options: PluginOptions; + loggerTestOnly: boolean; + logs: Array<{filename: string | null; event: LoggerEvent}>; +} { + // TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false + let validatePreserveExistingMemoizationGuarantees = false; + let target: CompilerReactTarget = '19'; + + /** + * Snap currently runs all fixtures without `validatePreserveExistingMemo` as + * most fixtures are interested in compilation output, not whether the + * compiler was able to preserve existing memo. + * + * TODO: flip the default. `useMemo` is rare in test fixtures -- fixtures that + * use useMemo should be explicit about whether this flag is enabled + */ + if (firstLine.includes('@validatePreserveExistingMemoizationGuarantees')) { + validatePreserveExistingMemoizationGuarantees = true; + } + + const loggerTestOnly = firstLine.includes('@loggerTestOnly'); + const logs: Array<{filename: string | null; event: LoggerEvent}> = []; + const logger: Logger = { + logEvent: (filename, event) => { + logs.push({filename, event}); + }, + debugLogIRs: debugIRLogger, + }; + + const config = parseConfigPragmaFn(firstLine, {compilationMode: 'all'}); + const options = { + ...config, + environment: { + ...config.environment, + moduleTypeProvider: makeSharedRuntimeTypeProvider({ + EffectEnum, + ValueKindEnum, + ValueReasonEnum, + }), + assertValidMutableRanges: true, + validatePreserveExistingMemoizationGuarantees, + }, + logger, + enableReanimatedCheck: false, + target, + }; + return {options, loggerTestOnly, logs}; +} + +export function parseInput( + input: string, + filename: string, + language: 'flow' | 'typescript', + sourceType: 'module' | 'script', +): BabelCore.types.File { + // Extract the first line to quickly check for custom test directives + if (language === 'flow') { + return HermesParser.parse(input, { + babel: true, + flow: 'all', + sourceFilename: filename, + sourceType, + enableExperimentalComponentSyntax: true, + enableExperimentalFlowMatchSyntax: true, + }); + } else { + return BabelParser.parse(input, { + sourceFilename: filename, + plugins: ['typescript', 'jsx', 'explicitResourceManagement'], + sourceType, + }); + } +} + +function getEvaluatorPresets( + language: 'typescript' | 'flow', +): Array { + const presets: Array = [ + { + plugins: [ + 'babel-plugin-fbt', + 'babel-plugin-fbt-runtime', + 'babel-plugin-idx', + ], + }, + ]; + presets.push( + language === 'typescript' + ? [ + '@babel/preset-typescript', + { + /** + * onlyRemoveTypeImports needs to be set as fbt imports + * would otherwise be removed by this pass. + * https://github.com/facebook/fbt/issues/49 + * https://github.com/facebook/sfbt/issues/72 + * https://dev.to/retyui/how-to-add-support-typescript-for-fbt-an-internationalization-framework-3lo0 + */ + onlyRemoveTypeImports: true, + }, + ] + : '@babel/preset-flow', + ); + + presets.push({ + plugins: ['@babel/plugin-syntax-jsx'], + }); + presets.push( + ['@babel/preset-react', {throwIfNamespace: false}], + { + plugins: ['@babel/plugin-transform-modules-commonjs'], + }, + { + plugins: [ + function BabelPluginRewriteRequirePath() { + return { + visitor: { + CallExpression(path: NodePath) { + const {callee} = path.node; + if (callee.type === 'Identifier' && callee.name === 'require') { + const arg = path.node.arguments[0]; + if (arg.type === 'StringLiteral') { + // rewrite to use relative import as eval happens in + // sprout/evaluator.ts + if (arg.value === 'shared-runtime') { + arg.value = './shared-runtime'; + } else if (arg.value === 'ReactForgetFeatureFlag') { + arg.value = './ReactForgetFeatureFlag'; + } else if (arg.value === 'useEffectWrapper') { + arg.value = './useEffectWrapper'; + } + } + } + }, + }, + }; + }, + ], + }, + ); + return presets; +} +async function format( + inputCode: string, + language: 'typescript' | 'flow', +): Promise { + return await prettier.format(inputCode, { + semi: true, + parser: language === 'typescript' ? 'babel-ts' : 'flow', + }); +} +const TypescriptEvaluatorPresets = getEvaluatorPresets('typescript'); +const FlowEvaluatorPresets = getEvaluatorPresets('flow'); + +export type TransformResult = { + forgetOutput: string; + logs: string | null; + evaluatorCode: { + original: string; + forget: string; + } | null; +}; + +export async function transformFixtureInput( + input: string, + fixturePath: string, + parseConfigPragmaFn: typeof ParseConfigPragma, + plugin: BabelCore.PluginObj, + includeEvaluator: boolean, + debugIRLogger: (value: CompilerPipelineValue) => void, + EffectEnum: typeof Effect, + ValueKindEnum: typeof ValueKind, + ValueReasonEnum: typeof ValueReason, +): Promise<{kind: 'ok'; value: TransformResult} | {kind: 'err'; msg: string}> { + // Extract the first line to quickly check for custom test directives + const firstLine = input.substring(0, input.indexOf('\n')); + + const language = parseLanguage(firstLine); + const sourceType = parseSourceType(firstLine); + // Preserve file extension as it determines typescript's babel transform + // mode (e.g. stripping types, parsing rules for brackets) + const filename = + path.basename(fixturePath) + (language === 'typescript' ? '.ts' : ''); + const inputAst = parseInput(input, filename, language, sourceType); + // Give babel transforms an absolute path as relative paths get prefixed + // with `cwd`, which is different across machines + const virtualFilepath = '/' + filename; + + const presets = + language === 'typescript' + ? TypescriptEvaluatorPresets + : FlowEvaluatorPresets; + + /** + * Get Forget compiled code + */ + const {options, loggerTestOnly, logs} = makePluginOptions( + firstLine, + parseConfigPragmaFn, + debugIRLogger, + EffectEnum, + ValueKindEnum, + ValueReasonEnum, + ); + const forgetResult = transformFromAstSync(inputAst, input, { + filename: virtualFilepath, + highlightCode: false, + retainLines: true, + compact: true, + plugins: [ + [plugin, options], + 'babel-plugin-fbt', + 'babel-plugin-fbt-runtime', + 'babel-plugin-idx', + ], + sourceType: 'module', + ast: includeEvaluator, + cloneInputAst: includeEvaluator, + configFile: false, + babelrc: false, + }); + invariant( + forgetResult?.code != null, + 'Expected BabelPluginReactForget to codegen successfully.', + ); + const forgetCode = forgetResult.code; + let evaluatorCode = null; + + if ( + includeEvaluator && + !SproutTodoFilter.has(fixturePath) && + !isExpectError(filename) + ) { + let forgetEval: string; + try { + invariant( + forgetResult?.ast != null, + 'Expected BabelPluginReactForget ast.', + ); + const result = transformFromAstSync(forgetResult.ast, forgetCode, { + presets, + filename: virtualFilepath, + configFile: false, + babelrc: false, + }); + if (result?.code == null) { + return { + kind: 'err', + msg: 'Unexpected error in forget transform pipeline - no code emitted', + }; + } else { + forgetEval = result.code; + } + } catch (e) { + return { + kind: 'err', + msg: 'Unexpected error in Forget transform pipeline: ' + e.message, + }; + } + + /** + * Get evaluator code for source (no Forget) + */ + let originalEval: string; + try { + const result = transformFromAstSync(inputAst, input, { + presets, + filename: virtualFilepath, + configFile: false, + babelrc: false, + }); + + if (result?.code == null) { + return { + kind: 'err', + msg: 'Unexpected error in non-forget transform pipeline - no code emitted', + }; + } else { + originalEval = result.code; + } + } catch (e) { + return { + kind: 'err', + msg: 'Unexpected error in non-forget transform pipeline: ' + e.message, + }; + } + evaluatorCode = { + forget: forgetEval, + original: originalEval, + }; + } + const forgetOutput = await format(forgetCode, language); + let formattedLogs = null; + if (loggerTestOnly && logs.length !== 0) { + formattedLogs = logs + .map(({event}) => { + return JSON.stringify(event, (key, value) => { + if ( + key === 'detail' && + value != null && + typeof value.serialize === 'function' + ) { + return value.serialize(); + } + return value; + }); + }) + .join('\n'); + } + const expectNothingCompiled = + firstLine.indexOf('@expectNothingCompiled') !== -1; + const successFailures = logs.filter( + log => + log.event.kind === 'CompileSuccess' || log.event.kind === 'CompileError', + ); + if (successFailures.length === 0 && !expectNothingCompiled) { + return { + kind: 'err', + msg: 'No success/failure events, add `// @expectNothingCompiled` to the first line if this is expected', + }; + } else if (successFailures.length !== 0 && expectNothingCompiled) { + return { + kind: 'err', + msg: 'Expected nothing to be compiled (from `// @expectNothingCompiled`), but some functions compiled or errored', + }; + } + const unexpectedThrows = logs.filter( + log => log.event.kind === 'CompileUnexpectedThrow', + ); + if (unexpectedThrows.length > 0) { + return { + kind: 'err', + msg: + `Compiler pass(es) threw instead of recording errors:\n` + + unexpectedThrows.map(l => (l.event as any).data).join('\n'), + }; + } + return { + kind: 'ok', + value: { + forgetOutput, + logs: formattedLogs, + evaluatorCode, + }, + }; +} diff --git a/compiler/packages/snap/src/constants.ts b/compiler/packages/snap/src/constants.ts new file mode 100644 index 000000000000..b5bd40f6b85a --- /dev/null +++ b/compiler/packages/snap/src/constants.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import path from 'path'; + +export const PROJECT_ROOT = path.join(process.cwd(), '..', '..'); + +// We assume this is run from `babel-plugin-react-compiler` +export const BABEL_PLUGIN_ROOT = path.normalize( + path.join(PROJECT_ROOT, 'packages', 'babel-plugin-react-compiler'), +); + +export const BABEL_PLUGIN_SRC = path.normalize( + path.join(BABEL_PLUGIN_ROOT, 'dist', 'index.js'), +); +export const PRINT_HIR_IMPORT = 'printFunctionWithOutlined'; +export const PRINT_REACTIVE_IR_IMPORT = 'printReactiveFunction'; +export const PARSE_CONFIG_PRAGMA_IMPORT = 'parseConfigPragmaForTests'; +export const FIXTURES_PATH = path.join( + BABEL_PLUGIN_ROOT, + 'src', + '__tests__', + 'fixtures', + 'compiler', +); +export const SNAPSHOT_EXTENSION = '.expect.md'; + +export const BABEL_PLUGIN_RUST_ROOT = path.normalize( + path.join(PROJECT_ROOT, 'packages', 'babel-plugin-react-compiler-rust'), +); +export const BABEL_PLUGIN_RUST_SRC = path.normalize( + path.join(BABEL_PLUGIN_RUST_ROOT, 'dist', 'index.js'), +); +export const CRATES_PATH = path.normalize( + path.join(PROJECT_ROOT, '..', 'crates'), +); diff --git a/compiler/packages/snap/src/fixture-utils.ts b/compiler/packages/snap/src/fixture-utils.ts new file mode 100644 index 000000000000..29f7d4ddfbb9 --- /dev/null +++ b/compiler/packages/snap/src/fixture-utils.ts @@ -0,0 +1,188 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import fs from 'fs/promises'; +import * as glob from 'glob'; +import path from 'path'; +import {FIXTURES_PATH, SNAPSHOT_EXTENSION} from './constants'; + +const INPUT_EXTENSIONS = [ + '.js', + '.cjs', + '.mjs', + '.ts', + '.cts', + '.mts', + '.jsx', + '.tsx', +]; + +export type TestFilter = { + paths: Array; +}; + +function stripExtension(filename: string, extensions: Array): string { + for (const ext of extensions) { + if (filename.endsWith(ext)) { + return filename.slice(0, -ext.length); + } + } + return filename; +} + +export function getBasename(fixture: TestFixture): string { + return stripExtension(path.basename(fixture.inputPath), INPUT_EXTENSIONS); +} +export function isExpectError(fixture: TestFixture | string): boolean { + const basename = typeof fixture === 'string' ? fixture : getBasename(fixture); + return basename.startsWith('error.') || basename.startsWith('todo.error'); +} + +export type TestFixture = + | { + fixturePath: string; + input: string | null; + inputPath: string; + snapshot: string | null; + snapshotPath: string; + } + | { + fixturePath: string; + input: null; + inputPath: string; + snapshot: string; + snapshotPath: string; + }; + +async function readInputFixtures( + rootDir: string, + filter: TestFilter | null, +): Promise> { + let inputFiles: Array; + if (filter == null) { + inputFiles = glob.sync(`**/*{${INPUT_EXTENSIONS.join(',')}}`, { + cwd: rootDir, + }); + } else { + inputFiles = ( + await Promise.all( + filter.paths.map(pattern => { + // If the pattern already has an extension other than .expect.md, + // search for the pattern directly. Otherwise, search for the + // pattern with the expected input extensions added. + // Eg + // `alias-while` => search for `alias-while{.js,.jsx,.ts,.tsx}` + // `alias-while.js` => search as-is + // `alias-while.expect.md` => search for `alias-while{.js,.jsx,.ts,.tsx}` + const patternWithoutExt = stripExtension(pattern, [ + ...INPUT_EXTENSIONS, + SNAPSHOT_EXTENSION, + ]); + const hasExtension = pattern !== patternWithoutExt; + const globPattern = + hasExtension && !pattern.endsWith(SNAPSHOT_EXTENSION) + ? pattern + : `${patternWithoutExt}{${INPUT_EXTENSIONS.join(',')}}`; + return glob.glob(globPattern, { + cwd: rootDir, + }); + }), + ) + ).flat(); + } + const inputs: Array> = + []; + for (const filePath of inputFiles) { + // Do not include extensions in unique identifier for fixture + const partialPath = stripExtension(filePath, INPUT_EXTENSIONS); + inputs.push( + fs.readFile(path.join(rootDir, filePath), 'utf8').then(input => { + return [ + partialPath, + { + value: input, + filepath: filePath, + }, + ]; + }), + ); + } + return new Map(await Promise.all(inputs)); +} +async function readOutputFixtures( + rootDir: string, + filter: TestFilter | null, +): Promise> { + let outputFiles: Array; + if (filter == null) { + outputFiles = glob.sync(`**/*${SNAPSHOT_EXTENSION}`, { + cwd: rootDir, + }); + } else { + outputFiles = ( + await Promise.all( + filter.paths.map(pattern => { + // Strip all extensions and find matching .expect.md files + const basenameWithoutExt = stripExtension(pattern, [ + ...INPUT_EXTENSIONS, + SNAPSHOT_EXTENSION, + ]); + return glob.glob(`${basenameWithoutExt}${SNAPSHOT_EXTENSION}`, { + cwd: rootDir, + }); + }), + ) + ).flat(); + } + const outputs: Array> = []; + for (const filePath of outputFiles) { + // Do not include extensions in unique identifier for fixture + const partialPath = stripExtension(filePath, [SNAPSHOT_EXTENSION]); + + const outputPath = path.join(rootDir, filePath); + const output: Promise<[string, string]> = fs + .readFile(outputPath, 'utf8') + .then(output => { + return [partialPath, output]; + }); + outputs.push(output); + } + return new Map(await Promise.all(outputs)); +} + +export async function getFixtures( + filter: TestFilter | null, +): Promise> { + const inputs = await readInputFixtures(FIXTURES_PATH, filter); + const outputs = await readOutputFixtures(FIXTURES_PATH, filter); + + const fixtures: Map = new Map(); + for (const [partialPath, {value, filepath}] of inputs) { + const output = outputs.get(partialPath) ?? null; + fixtures.set(partialPath, { + fixturePath: partialPath, + input: value, + inputPath: filepath, + snapshot: output, + snapshotPath: path.join(FIXTURES_PATH, partialPath) + SNAPSHOT_EXTENSION, + }); + } + + for (const [partialPath, output] of outputs) { + if (!fixtures.has(partialPath)) { + fixtures.set(partialPath, { + fixturePath: partialPath, + input: null, + inputPath: 'none', + snapshot: output, + snapshotPath: + path.join(FIXTURES_PATH, partialPath) + SNAPSHOT_EXTENSION, + }); + } + } + return fixtures; +} diff --git a/compiler/packages/snap/src/main.ts b/compiler/packages/snap/src/main.ts new file mode 100644 index 000000000000..9e5ab53e5c6d --- /dev/null +++ b/compiler/packages/snap/src/main.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {fork} from 'child_process'; +import invariant from 'invariant'; +import process from 'process'; +import * as readline from 'readline'; +import {hideBin} from 'yargs/helpers'; + +readline.emitKeypressEvents(process.stdin); + +if (process.stdin.isTTY) { + process.stdin.setRawMode(true); +} + +process.stdin.on('keypress', function (_, key) { + if (key && key.name === 'c' && key.ctrl) { + // handle sigint + if (childProc) { + console.log('Interrupted!!'); + childProc.kill('SIGINT'); + childProc.unref(); + process.exit(-1); + } + } +}); + +const childProc = fork(require.resolve('./runner.js'), hideBin(process.argv), { + // for some reason, keypress events aren't sent to handlers in both processes + // when we `inherit` stdin. + // pipe stdout and stderr so we can silence child process after parent exits + stdio: ['pipe', 'pipe', 'pipe', 'ipc'], + // forward existing env variables, like `NODE_OPTIONS` which VSCode uses to attach + // its debugger + env: {...process.env, FORCE_COLOR: 'true'}, +}); + +invariant( + childProc.stdin && childProc.stdout && childProc.stderr, + 'Expected forked process to have piped stdio', +); +process.stdin.pipe(childProc.stdin); +childProc.stdout.pipe(process.stdout); +childProc.stderr.pipe(process.stderr); + +childProc.on('exit', code => { + process.exit(code ?? -1); +}); diff --git a/compiler/packages/snap/src/minimize.ts b/compiler/packages/snap/src/minimize.ts new file mode 100644 index 000000000000..e9574b1759c1 --- /dev/null +++ b/compiler/packages/snap/src/minimize.ts @@ -0,0 +1,2299 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {PluginObj} from '@babel/core'; +import {transformFromAstSync} from '@babel/core'; +import generate from '@babel/generator'; +import traverse from '@babel/traverse'; +import * as t from '@babel/types'; +import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/Utils/TestUtils'; +import {parseInput} from './compiler.js'; +import { + PARSE_CONFIG_PRAGMA_IMPORT, + BABEL_PLUGIN_SRC, + BABEL_PLUGIN_RUST_SRC, +} from './constants.js'; + +type CompileSuccess = {kind: 'success'}; +type CompileParseError = {kind: 'parse_error'; message: string}; +type CompileErrors = { + kind: 'errors'; + errors: Array<{category: string; reason: string; description: string | null}>; +}; +type CompileResult = CompileSuccess | CompileParseError | CompileErrors; + +/** + * Compile code and extract error information + */ +function compileAndGetError( + code: string, + filename: string, + language: 'flow' | 'typescript', + sourceType: 'module' | 'script', + plugin: PluginObj, + parseConfigPragmaFn: typeof ParseConfigPragma, +): CompileResult { + let ast: t.File; + try { + ast = parseInput(code, filename, language, sourceType); + } catch (e: unknown) { + return {kind: 'parse_error', message: (e as Error).message}; + } + + const firstLine = code.substring(0, code.indexOf('\n')); + const config = parseConfigPragmaFn(firstLine, {compilationMode: 'all'}); + const options = { + ...config, + environment: { + ...config.environment, + }, + logger: { + logEvent: () => {}, + debugLogIRs: () => {}, + }, + enableReanimatedCheck: false, + }; + + try { + transformFromAstSync(ast, code, { + filename: '/' + filename, + highlightCode: false, + retainLines: true, + compact: true, + plugins: [[plugin, options]], + sourceType: 'module', + ast: false, + cloneInputAst: true, + configFile: false, + babelrc: false, + }); + return {kind: 'success'}; + } catch (e: unknown) { + const error = e as Error & { + details?: Array<{ + category: string; + reason: string; + description: string | null; + }>; + }; + // Check if this is a CompilerError with details + if (error.details && error.details.length > 0) { + return { + kind: 'errors', + errors: error.details.map(detail => ({ + category: detail.category, + reason: detail.reason, + description: detail.description, + })), + }; + } + // Fallback for other errors - use error name/message + return { + kind: 'errors', + errors: [ + { + category: error.name ?? 'Error', + reason: error.message, + description: null, + }, + ], + }; + } +} + +/** + * Check if two compile errors match + */ +function errorsMatch(a: CompileErrors, b: CompileResult): boolean { + if (b.kind !== 'errors') { + return false; + } + if (a.errors.length !== b.errors.length) { + return false; + } + for (let i = 0; i < a.errors.length; i++) { + if ( + a.errors[i].category !== b.errors[i].category || + a.errors[i].reason !== b.errors[i].reason || + a.errors[i].description !== b.errors[i].description + ) { + return false; + } + } + return true; +} + +/** + * Convert AST to code string + */ +function astToCode(ast: t.File): string { + return generate(ast).code; +} + +/** + * Clone an AST node deeply + */ +function cloneAst(ast: t.File): t.File { + return t.cloneNode(ast, true); +} + +/** + * Generator that yields ASTs with statements removed one at a time + */ +function* removeStatements(ast: t.File): Generator { + // Collect all statement locations: which container (by index) and which statement index + const statementLocations: Array<{containerIndex: number; stmtIndex: number}> = + []; + let containerIndex = 0; + + t.traverseFast(ast, node => { + if (t.isBlockStatement(node) || t.isProgram(node)) { + const body = node.body as t.Statement[]; + // Iterate in reverse order so removing later statements first + for (let i = body.length - 1; i >= 0; i--) { + statementLocations.push({containerIndex, stmtIndex: i}); + } + containerIndex++; + } + }); + + for (const { + containerIndex: targetContainerIdx, + stmtIndex, + } of statementLocations) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isBlockStatement(node) || t.isProgram(node)) { + if (idx === targetContainerIdx) { + const body = node.body as t.Statement[]; + if (stmtIndex < body.length) { + body.splice(stmtIndex, 1); + modified = true; + } + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that yields ASTs with call arguments removed one at a time + */ +function* removeCallArguments(ast: t.File): Generator { + // Collect all call expressions with their argument counts + const callSites: Array<{callIndex: number; argCount: number}> = []; + let callIndex = 0; + t.traverseFast(ast, node => { + if (t.isCallExpression(node) && node.arguments.length > 0) { + callSites.push({callIndex, argCount: node.arguments.length}); + callIndex++; + } + }); + + // For each call site, try removing each argument one at a time (from end to start) + for (const {callIndex: targetCallIdx, argCount} of callSites) { + for (let argIdx = argCount - 1; argIdx >= 0; argIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isCallExpression(node) && node.arguments.length > 0) { + if (idx === targetCallIdx && argIdx < node.arguments.length) { + node.arguments.splice(argIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that yields ASTs with function parameters removed one at a time + */ +function* removeFunctionParameters(ast: t.File): Generator { + // Collect all functions with parameters + const funcSites: Array<{funcIndex: number; paramCount: number}> = []; + let funcIndex = 0; + t.traverseFast(ast, node => { + if (t.isFunction(node) && node.params.length > 0) { + funcSites.push({funcIndex, paramCount: node.params.length}); + funcIndex++; + } + }); + + // For each function, try removing each parameter (from end to start) + for (const {funcIndex: targetFuncIdx, paramCount} of funcSites) { + for (let paramIdx = paramCount - 1; paramIdx >= 0; paramIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isFunction(node) && node.params.length > 0) { + if (idx === targetFuncIdx && paramIdx < node.params.length) { + node.params.splice(paramIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that simplifies call expressions by replacing them with their arguments. + * For single argument: foo(x) -> x + * For multiple arguments: foo(x, y) -> [x, y] + */ +function* simplifyCallExpressions(ast: t.File): Generator { + // Count call expressions with arguments + let callCount = 0; + t.traverseFast(ast, node => { + if (t.isCallExpression(node) && node.arguments.length > 0) { + callCount++; + } + }); + + // For each call, try replacing with arguments + for (let targetIdx = 0; targetIdx < callCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + CallExpression(path) { + if (modified) return; + if (path.node.arguments.length > 0 && idx === targetIdx) { + const args = path.node.arguments; + // Filter to only Expression arguments (not SpreadElement) + const exprArgs = args.filter((arg): arg is t.Expression => + t.isExpression(arg), + ); + if (exprArgs.length === 0) { + idx++; + return; + } + if (exprArgs.length === 1) { + // Single argument: replace call with the argument + path.replaceWith(exprArgs[0]); + } else { + // Multiple arguments: replace call with array of arguments + path.replaceWith(t.arrayExpression(exprArgs)); + } + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Also try replacing with each individual argument for multi-arg calls + for (let targetIdx = 0; targetIdx < callCount; targetIdx++) { + // First, find the arg count for this call + let argCount = 0; + let currentIdx = 0; + t.traverseFast(ast, node => { + if (t.isCallExpression(node) && node.arguments.length > 0) { + if (currentIdx === targetIdx) { + argCount = node.arguments.length; + } + currentIdx++; + } + }); + + // Try replacing with each argument individually + for (let argIdx = 0; argIdx < argCount; argIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + CallExpression(path) { + if (modified) return; + if (path.node.arguments.length > 0 && idx === targetIdx) { + const arg = path.node.arguments[argIdx]; + if (t.isExpression(arg)) { + path.replaceWith(arg); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that simplifies conditional expressions (a ? b : c) -> a, b, or c + */ +function* simplifyConditionals(ast: t.File): Generator { + // Count conditionals + let condCount = 0; + t.traverseFast(ast, node => { + if (t.isConditionalExpression(node)) { + condCount++; + } + }); + + // Try replacing with test condition + for (let targetIdx = 0; targetIdx < condCount; targetIdx++) { + const cloned = cloneAst(ast); + let modified = false; + let idx = 0; + + traverse(cloned, { + ConditionalExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.test); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with consequent + for (let targetIdx = 0; targetIdx < condCount; targetIdx++) { + const cloned = cloneAst(ast); + let modified = false; + let idx = 0; + + traverse(cloned, { + ConditionalExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.consequent); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Also try replacing with alternate + for (let targetIdx = 0; targetIdx < condCount; targetIdx++) { + const cloned = cloneAst(ast); + let modified = false; + let idx = 0; + + traverse(cloned, { + ConditionalExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.alternate); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies logical expressions (a && b) -> a or b + */ +function* simplifyLogicalExpressions(ast: t.File): Generator { + // Count logical expressions + let logicalCount = 0; + t.traverseFast(ast, node => { + if (t.isLogicalExpression(node)) { + logicalCount++; + } + }); + + // Try replacing with left side + for (let targetIdx = 0; targetIdx < logicalCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + LogicalExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.left); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with right side + for (let targetIdx = 0; targetIdx < logicalCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + LogicalExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.right); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies optional chains (a?.b) -> a.b + */ +function* simplifyOptionalChains(ast: t.File): Generator { + // Count optional expressions + let optionalCount = 0; + t.traverseFast(ast, node => { + if ( + t.isOptionalMemberExpression(node) || + t.isOptionalCallExpression(node) + ) { + optionalCount++; + } + }); + + for (let targetIdx = 0; targetIdx < optionalCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + OptionalMemberExpression(path) { + if (modified) return; + if (idx === targetIdx) { + const {object, property, computed} = path.node; + path.replaceWith(t.memberExpression(object, property, computed)); + modified = true; + } + idx++; + }, + OptionalCallExpression(path) { + if (modified) return; + if (idx === targetIdx) { + const {callee, arguments: args} = path.node; + if (t.isExpression(callee)) { + path.replaceWith(t.callExpression(callee, args)); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies await expressions: await expr -> expr + */ +function* simplifyAwaitExpressions(ast: t.File): Generator { + // Count await expressions + let awaitCount = 0; + t.traverseFast(ast, node => { + if (t.isAwaitExpression(node)) { + awaitCount++; + } + }); + + for (let targetIdx = 0; targetIdx < awaitCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + AwaitExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.argument); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies if statements: + * - Replace with test expression (as expression statement) + * - Replace with consequent block + * - Replace with alternate block (if present) + */ +function* simplifyIfStatements(ast: t.File): Generator { + // Count if statements + let ifCount = 0; + t.traverseFast(ast, node => { + if (t.isIfStatement(node)) { + ifCount++; + } + }); + + // Try replacing with test expression + for (let targetIdx = 0; targetIdx < ifCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + IfStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(t.expressionStatement(path.node.test)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with consequent + for (let targetIdx = 0; targetIdx < ifCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + IfStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.consequent); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with alternate (if present) + for (let targetIdx = 0; targetIdx < ifCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + IfStatement(path) { + if (modified) return; + if (idx === targetIdx && path.node.alternate) { + path.replaceWith(path.node.alternate); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies switch statements: + * - Replace with discriminant expression + * - Replace with each case's consequent statements + */ +function* simplifySwitchStatements(ast: t.File): Generator { + // Count switch statements + let switchCount = 0; + t.traverseFast(ast, node => { + if (t.isSwitchStatement(node)) { + switchCount++; + } + }); + + // Try replacing with discriminant + for (let targetIdx = 0; targetIdx < switchCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + SwitchStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(t.expressionStatement(path.node.discriminant)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // For each switch, try replacing with each case's body + for (let targetIdx = 0; targetIdx < switchCount; targetIdx++) { + // Find case count for this switch + let caseCount = 0; + let currentIdx = 0; + t.traverseFast(ast, node => { + if (t.isSwitchStatement(node)) { + if (currentIdx === targetIdx) { + caseCount = node.cases.length; + } + currentIdx++; + } + }); + + for (let caseIdx = 0; caseIdx < caseCount; caseIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + SwitchStatement(path) { + if (modified) return; + if (idx === targetIdx) { + const switchCase = path.node.cases[caseIdx]; + if (switchCase && switchCase.consequent.length > 0) { + path.replaceWithMultiple(switchCase.consequent); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that simplifies while statements: + * - Replace with test expression + * - Replace with body + */ +function* simplifyWhileStatements(ast: t.File): Generator { + // Count while statements + let whileCount = 0; + t.traverseFast(ast, node => { + if (t.isWhileStatement(node)) { + whileCount++; + } + }); + + // Try replacing with test + for (let targetIdx = 0; targetIdx < whileCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + WhileStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(t.expressionStatement(path.node.test)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with body + for (let targetIdx = 0; targetIdx < whileCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + WhileStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.body); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies do-while statements: + * - Replace with test expression + * - Replace with body + */ +function* simplifyDoWhileStatements(ast: t.File): Generator { + // Count do-while statements + let doWhileCount = 0; + t.traverseFast(ast, node => { + if (t.isDoWhileStatement(node)) { + doWhileCount++; + } + }); + + // Try replacing with test + for (let targetIdx = 0; targetIdx < doWhileCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + DoWhileStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(t.expressionStatement(path.node.test)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with body + for (let targetIdx = 0; targetIdx < doWhileCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + DoWhileStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.body); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies for statements: + * - Replace with init (if expression) + * - Replace with test expression + * - Replace with update expression + * - Replace with body + */ +function* simplifyForStatements(ast: t.File): Generator { + // Count for statements + let forCount = 0; + t.traverseFast(ast, node => { + if (t.isForStatement(node)) { + forCount++; + } + }); + + // Try replacing with init (if it's an expression) + for (let targetIdx = 0; targetIdx < forCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForStatement(path) { + if (modified) return; + if (idx === targetIdx && path.node.init) { + if (t.isExpression(path.node.init)) { + path.replaceWith(t.expressionStatement(path.node.init)); + } else { + // It's a VariableDeclaration + path.replaceWith(path.node.init); + } + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with test + for (let targetIdx = 0; targetIdx < forCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForStatement(path) { + if (modified) return; + if (idx === targetIdx && path.node.test) { + path.replaceWith(t.expressionStatement(path.node.test)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with update + for (let targetIdx = 0; targetIdx < forCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForStatement(path) { + if (modified) return; + if (idx === targetIdx && path.node.update) { + path.replaceWith(t.expressionStatement(path.node.update)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with body + for (let targetIdx = 0; targetIdx < forCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.body); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies for-in statements: + * - Replace with left (variable declaration or expression) + * - Replace with right expression + * - Replace with body + */ +function* simplifyForInStatements(ast: t.File): Generator { + // Count for-in statements + let forInCount = 0; + t.traverseFast(ast, node => { + if (t.isForInStatement(node)) { + forInCount++; + } + }); + + // Try replacing with left + for (let targetIdx = 0; targetIdx < forInCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForInStatement(path) { + if (modified) return; + if (idx === targetIdx) { + const left = path.node.left; + if (t.isExpression(left)) { + path.replaceWith(t.expressionStatement(left)); + } else { + path.replaceWith(left); + } + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with right + for (let targetIdx = 0; targetIdx < forInCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForInStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(t.expressionStatement(path.node.right)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with body + for (let targetIdx = 0; targetIdx < forInCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForInStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.body); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies for-of statements: + * - Replace with left (variable declaration or expression) + * - Replace with right expression + * - Replace with body + */ +function* simplifyForOfStatements(ast: t.File): Generator { + // Count for-of statements + let forOfCount = 0; + t.traverseFast(ast, node => { + if (t.isForOfStatement(node)) { + forOfCount++; + } + }); + + // Try replacing with left + for (let targetIdx = 0; targetIdx < forOfCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForOfStatement(path) { + if (modified) return; + if (idx === targetIdx) { + const left = path.node.left; + if (t.isExpression(left)) { + path.replaceWith(t.expressionStatement(left)); + } else { + path.replaceWith(left); + } + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with right + for (let targetIdx = 0; targetIdx < forOfCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForOfStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(t.expressionStatement(path.node.right)); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with body + for (let targetIdx = 0; targetIdx < forOfCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ForOfStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.body); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies variable declarations by removing init expressions. + * let x = expr; -> let x; + * var x = expr; -> var x; + * Note: const without init is invalid, so we skip const declarations. + */ +function* simplifyVariableDeclarations(ast: t.File): Generator { + // Collect all variable declarators with init expressions (excluding const) + const declaratorSites: Array<{declIndex: number}> = []; + let declIndex = 0; + t.traverseFast(ast, node => { + if (t.isVariableDeclaration(node) && node.kind !== 'const') { + for (const declarator of node.declarations) { + if (declarator.init) { + declaratorSites.push({declIndex}); + declIndex++; + } + } + } + }); + + // Try removing init from each declarator + for (const {declIndex: targetDeclIdx} of declaratorSites) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isVariableDeclaration(node) && node.kind !== 'const') { + for (const declarator of node.declarations) { + if (declarator.init) { + if (idx === targetDeclIdx) { + declarator.init = null; + modified = true; + return; + } + idx++; + } + } + } + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies try/catch/finally statements: + * - Replace with try block contents + * - Replace with catch block contents (if present) + * - Replace with finally block contents (if present) + */ +function* simplifyTryStatements(ast: t.File): Generator { + // Count try statements + let tryCount = 0; + t.traverseFast(ast, node => { + if (t.isTryStatement(node)) { + tryCount++; + } + }); + + // Try replacing with try block contents + for (let targetIdx = 0; targetIdx < tryCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + TryStatement(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.block); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with catch block contents (if present) + for (let targetIdx = 0; targetIdx < tryCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + TryStatement(path) { + if (modified) return; + if (idx === targetIdx && path.node.handler) { + path.replaceWith(path.node.handler.body); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with finally block contents (if present) + for (let targetIdx = 0; targetIdx < tryCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + TryStatement(path) { + if (modified) return; + if (idx === targetIdx && path.node.finalizer) { + path.replaceWith(path.node.finalizer); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies single-statement block statements: + * { statement } -> statement + */ +function* simplifySingleStatementBlocks(ast: t.File): Generator { + // Count block statements with exactly one statement + let blockCount = 0; + t.traverseFast(ast, node => { + if (t.isBlockStatement(node) && node.body.length === 1) { + blockCount++; + } + }); + + for (let targetIdx = 0; targetIdx < blockCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + BlockStatement(path) { + if (modified) return; + if (path.node.body.length === 1 && idx === targetIdx) { + // Don't unwrap blocks that require BlockStatement syntax + if ( + t.isFunction(path.parent) || + t.isCatchClause(path.parent) || + t.isClassMethod(path.parent) || + t.isObjectMethod(path.parent) || + t.isTryStatement(path.parent) + ) { + idx++; + return; + } + path.replaceWith(path.node.body[0]); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that removes array elements one at a time + */ +function* removeArrayElements(ast: t.File): Generator { + // Collect all array expressions with their element counts + const arraySites: Array<{arrayIndex: number; elementCount: number}> = []; + let arrayIndex = 0; + t.traverseFast(ast, node => { + if (t.isArrayExpression(node) && node.elements.length > 0) { + arraySites.push({arrayIndex, elementCount: node.elements.length}); + arrayIndex++; + } + }); + + // For each array, try removing each element one at a time (from end to start) + for (const {arrayIndex: targetArrayIdx, elementCount} of arraySites) { + for (let elemIdx = elementCount - 1; elemIdx >= 0; elemIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isArrayExpression(node) && node.elements.length > 0) { + if (idx === targetArrayIdx && elemIdx < node.elements.length) { + node.elements.splice(elemIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that removes JSX element attributes (props) one at a time + */ +function* removeJSXAttributes(ast: t.File): Generator { + // Collect all JSX elements with their attribute counts + const jsxSites: Array<{jsxIndex: number; attrCount: number}> = []; + let jsxIndex = 0; + t.traverseFast(ast, node => { + if (t.isJSXOpeningElement(node) && node.attributes.length > 0) { + jsxSites.push({jsxIndex, attrCount: node.attributes.length}); + jsxIndex++; + } + }); + + // For each JSX element, try removing each attribute one at a time (from end to start) + for (const {jsxIndex: targetJsxIdx, attrCount} of jsxSites) { + for (let attrIdx = attrCount - 1; attrIdx >= 0; attrIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isJSXOpeningElement(node) && node.attributes.length > 0) { + if (idx === targetJsxIdx && attrIdx < node.attributes.length) { + node.attributes.splice(attrIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that removes JSX element children one at a time + */ +function* removeJSXChildren(ast: t.File): Generator { + // Collect all JSX elements with children + const jsxSites: Array<{jsxIndex: number; childCount: number}> = []; + let jsxIndex = 0; + t.traverseFast(ast, node => { + if (t.isJSXElement(node) && node.children.length > 0) { + jsxSites.push({jsxIndex, childCount: node.children.length}); + jsxIndex++; + } + }); + + // For each JSX element, try removing each child one at a time (from end to start) + for (const {jsxIndex: targetJsxIdx, childCount} of jsxSites) { + for (let childIdx = childCount - 1; childIdx >= 0; childIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isJSXElement(node) && node.children.length > 0) { + if (idx === targetJsxIdx && childIdx < node.children.length) { + node.children.splice(childIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that removes JSX fragment children one at a time + */ +function* removeJSXFragmentChildren(ast: t.File): Generator { + // Collect all JSX fragments with children + const fragmentSites: Array<{fragIndex: number; childCount: number}> = []; + let fragIndex = 0; + t.traverseFast(ast, node => { + if (t.isJSXFragment(node) && node.children.length > 0) { + fragmentSites.push({fragIndex, childCount: node.children.length}); + fragIndex++; + } + }); + + // For each fragment, try removing each child one at a time (from end to start) + for (const {fragIndex: targetFragIdx, childCount} of fragmentSites) { + for (let childIdx = childCount - 1; childIdx >= 0; childIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isJSXFragment(node) && node.children.length > 0) { + if (idx === targetFragIdx && childIdx < node.children.length) { + node.children.splice(childIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that replaces single-element arrays with the element itself + */ +function* simplifySingleElementArrays(ast: t.File): Generator { + // Count single-element arrays + let arrayCount = 0; + t.traverseFast(ast, node => { + if (t.isArrayExpression(node) && node.elements.length === 1) { + arrayCount++; + } + }); + + for (let targetIdx = 0; targetIdx < arrayCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ArrayExpression(path) { + if (modified) return; + if (path.node.elements.length === 1 && idx === targetIdx) { + const elem = path.node.elements[0]; + if (t.isExpression(elem)) { + path.replaceWith(elem); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that replaces single-property objects with the property value. + * For regular properties: {key: value} -> value + * For computed properties: {[key]: value} -> key (also try value) + */ +function* simplifySinglePropertyObjects(ast: t.File): Generator { + // Count single-property objects + let objectCount = 0; + t.traverseFast(ast, node => { + if (t.isObjectExpression(node) && node.properties.length === 1) { + objectCount++; + } + }); + + // Try replacing with value + for (let targetIdx = 0; targetIdx < objectCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ObjectExpression(path) { + if (modified) return; + if (path.node.properties.length === 1 && idx === targetIdx) { + const prop = path.node.properties[0]; + if (t.isObjectProperty(prop) && t.isExpression(prop.value)) { + path.replaceWith(prop.value); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // For computed properties, also try replacing with key + for (let targetIdx = 0; targetIdx < objectCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + ObjectExpression(path) { + if (modified) return; + if (path.node.properties.length === 1 && idx === targetIdx) { + const prop = path.node.properties[0]; + if ( + t.isObjectProperty(prop) && + prop.computed && + t.isExpression(prop.key) + ) { + path.replaceWith(prop.key); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that removes object properties one at a time + */ +function* removeObjectProperties(ast: t.File): Generator { + // Collect all object expressions with their property counts + const objectSites: Array<{objectIndex: number; propCount: number}> = []; + let objectIndex = 0; + t.traverseFast(ast, node => { + if (t.isObjectExpression(node) && node.properties.length > 0) { + objectSites.push({objectIndex, propCount: node.properties.length}); + objectIndex++; + } + }); + + // For each object, try removing each property one at a time (from end to start) + for (const {objectIndex: targetObjIdx, propCount} of objectSites) { + for (let propIdx = propCount - 1; propIdx >= 0; propIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isObjectExpression(node) && node.properties.length > 0) { + if (idx === targetObjIdx && propIdx < node.properties.length) { + node.properties.splice(propIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that removes elements from array destructuring patterns one at a time + */ +function* removeArrayPatternElements(ast: t.File): Generator { + // Collect all array patterns with elements + const patternSites: Array<{patternIndex: number; elementCount: number}> = []; + let patternIndex = 0; + t.traverseFast(ast, node => { + if (t.isArrayPattern(node) && node.elements.length > 0) { + patternSites.push({patternIndex, elementCount: node.elements.length}); + patternIndex++; + } + }); + + // For each pattern, try removing each element (from end to start) + for (const {patternIndex: targetPatternIdx, elementCount} of patternSites) { + for (let elemIdx = elementCount - 1; elemIdx >= 0; elemIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isArrayPattern(node) && node.elements.length > 0) { + if (idx === targetPatternIdx && elemIdx < node.elements.length) { + node.elements.splice(elemIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that removes properties from object destructuring patterns one at a time + */ +function* removeObjectPatternProperties(ast: t.File): Generator { + // Collect all object patterns with properties + const patternSites: Array<{patternIndex: number; propCount: number}> = []; + let patternIndex = 0; + t.traverseFast(ast, node => { + if (t.isObjectPattern(node) && node.properties.length > 0) { + patternSites.push({patternIndex, propCount: node.properties.length}); + patternIndex++; + } + }); + + // For each pattern, try removing each property (from end to start) + for (const {patternIndex: targetPatternIdx, propCount} of patternSites) { + for (let propIdx = propCount - 1; propIdx >= 0; propIdx--) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + t.traverseFast(cloned, node => { + if (modified) return; + if (t.isObjectPattern(node) && node.properties.length > 0) { + if (idx === targetPatternIdx && propIdx < node.properties.length) { + node.properties.splice(propIdx, 1); + modified = true; + } + idx++; + } + }); + + if (modified) { + yield cloned; + } + } + } +} + +/** + * Generator that simplifies assignment expressions (a = b) -> a or b + */ +function* simplifyAssignmentExpressions(ast: t.File): Generator { + // Count assignment expressions + let assignmentCount = 0; + t.traverseFast(ast, node => { + if (t.isAssignmentExpression(node)) { + assignmentCount++; + } + }); + + // Try replacing with left side (assignment target) + for (let targetIdx = 0; targetIdx < assignmentCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + AssignmentExpression(path) { + if (modified) return; + if (idx === targetIdx) { + const left = path.node.left; + if (t.isExpression(left)) { + path.replaceWith(left); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with right side (assignment value) + for (let targetIdx = 0; targetIdx < assignmentCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + AssignmentExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.right); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies binary expressions (a + b) -> a or b + */ +function* simplifyBinaryExpressions(ast: t.File): Generator { + // Count binary expressions + let binaryCount = 0; + t.traverseFast(ast, node => { + if (t.isBinaryExpression(node)) { + binaryCount++; + } + }); + + // Try replacing with left side + for (let targetIdx = 0; targetIdx < binaryCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + BinaryExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.left); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // Try replacing with right side + for (let targetIdx = 0; targetIdx < binaryCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + BinaryExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.right); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Generator that simplifies member expressions (obj.value) -> obj + * For computed expressions: obj[key] -> obj or key + */ +function* simplifyMemberExpressions(ast: t.File): Generator { + // Count member expressions + let memberCount = 0; + t.traverseFast(ast, node => { + if (t.isMemberExpression(node)) { + memberCount++; + } + }); + + // Try replacing with object + for (let targetIdx = 0; targetIdx < memberCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + MemberExpression(path) { + if (modified) return; + if (idx === targetIdx) { + path.replaceWith(path.node.object); + modified = true; + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } + + // For computed expressions, also try replacing with key + for (let targetIdx = 0; targetIdx < memberCount; targetIdx++) { + const cloned = cloneAst(ast); + let idx = 0; + let modified = false; + + traverse(cloned, { + MemberExpression(path) { + if (modified) return; + if (idx === targetIdx && path.node.computed) { + const property = path.node.property; + if (t.isExpression(property)) { + path.replaceWith(property); + modified = true; + } + } + idx++; + }, + }); + + if (modified) { + yield cloned; + } + } +} + +/** + * Helper to collect all unique identifier names in the AST + */ +function collectUniqueIdentifierNames(ast: t.File): Set { + const names = new Set(); + t.traverseFast(ast, node => { + if (t.isIdentifier(node)) { + names.add(node.name); + } + }); + return names; +} + +/** + * Helper to rename all occurrences of an identifier throughout the AST + */ +function renameAllIdentifiers( + ast: t.File, + oldName: string, + newName: string, +): boolean { + let modified = false; + t.traverseFast(ast, node => { + if (t.isIdentifier(node) && node.name === oldName) { + node.name = newName; + modified = true; + } + }); + return modified; +} + +/** + * Generator that simplifies identifiers by removing "on" prefix. + * onClick -> Click + */ +function* simplifyIdentifiersRemoveOnPrefix(ast: t.File): Generator { + const names = collectUniqueIdentifierNames(ast); + + for (const name of names) { + // Check if name starts with "on" followed by uppercase letter + if ( + name.length > 2 && + name.startsWith('on') && + name[2] === name[2].toUpperCase() + ) { + const newName = name.slice(2); + // Skip if the new name would conflict with an existing identifier + if (names.has(newName)) { + continue; + } + const cloned = cloneAst(ast); + if (renameAllIdentifiers(cloned, name, newName)) { + yield cloned; + } + } + } +} + +/** + * Generator that simplifies identifiers by removing "Ref" suffix. + * inputRef -> input + */ +function* simplifyIdentifiersRemoveRefSuffix(ast: t.File): Generator { + const names = collectUniqueIdentifierNames(ast); + + for (const name of names) { + // Check if name ends with "Ref" and has more characters before it + if (name.length > 3 && name.endsWith('Ref')) { + const newName = name.slice(0, -3); + // Skip if the new name would conflict with an existing identifier + if (names.has(newName)) { + continue; + } + // Skip if new name would be empty or just whitespace + if (newName.length === 0) { + continue; + } + const cloned = cloneAst(ast); + if (renameAllIdentifiers(cloned, name, newName)) { + yield cloned; + } + } + } +} + +/** + * Generator that rewrites "ref" identifier to "ref_" to avoid conflicts. + */ +function* simplifyIdentifiersRenameRef(ast: t.File): Generator { + const names = collectUniqueIdentifierNames(ast); + + if (names.has('ref')) { + // Only rename if ref_ doesn't already exist + if (!names.has('ref_')) { + const cloned = cloneAst(ast); + if (renameAllIdentifiers(cloned, 'ref', 'ref_')) { + yield cloned; + } + } + } +} + +/** + * All simplification strategies in order of priority (coarse to fine) + */ +const simplificationStrategies = [ + {name: 'removeStatements', generator: removeStatements}, + {name: 'removeCallArguments', generator: removeCallArguments}, + {name: 'removeFunctionParameters', generator: removeFunctionParameters}, + {name: 'removeArrayElements', generator: removeArrayElements}, + {name: 'removeObjectProperties', generator: removeObjectProperties}, + {name: 'removeArrayPatternElements', generator: removeArrayPatternElements}, + { + name: 'removeObjectPatternProperties', + generator: removeObjectPatternProperties, + }, + {name: 'removeJSXAttributes', generator: removeJSXAttributes}, + {name: 'removeJSXChildren', generator: removeJSXChildren}, + {name: 'removeJSXFragmentChildren', generator: removeJSXFragmentChildren}, + {name: 'simplifyCallExpressions', generator: simplifyCallExpressions}, + {name: 'simplifyConditionals', generator: simplifyConditionals}, + {name: 'simplifyLogicalExpressions', generator: simplifyLogicalExpressions}, + {name: 'simplifyBinaryExpressions', generator: simplifyBinaryExpressions}, + { + name: 'simplifyAssignmentExpressions', + generator: simplifyAssignmentExpressions, + }, + {name: 'simplifySingleElementArrays', generator: simplifySingleElementArrays}, + { + name: 'simplifySinglePropertyObjects', + generator: simplifySinglePropertyObjects, + }, + {name: 'simplifyMemberExpressions', generator: simplifyMemberExpressions}, + {name: 'simplifyOptionalChains', generator: simplifyOptionalChains}, + {name: 'simplifyAwaitExpressions', generator: simplifyAwaitExpressions}, + {name: 'simplifyIfStatements', generator: simplifyIfStatements}, + {name: 'simplifySwitchStatements', generator: simplifySwitchStatements}, + {name: 'simplifyWhileStatements', generator: simplifyWhileStatements}, + {name: 'simplifyDoWhileStatements', generator: simplifyDoWhileStatements}, + {name: 'simplifyForStatements', generator: simplifyForStatements}, + {name: 'simplifyForInStatements', generator: simplifyForInStatements}, + {name: 'simplifyForOfStatements', generator: simplifyForOfStatements}, + { + name: 'simplifyVariableDeclarations', + generator: simplifyVariableDeclarations, + }, + {name: 'simplifyTryStatements', generator: simplifyTryStatements}, + { + name: 'simplifySingleStatementBlocks', + generator: simplifySingleStatementBlocks, + }, + { + name: 'simplifyIdentifiersRemoveOnPrefix', + generator: simplifyIdentifiersRemoveOnPrefix, + }, + { + name: 'simplifyIdentifiersRemoveRefSuffix', + generator: simplifyIdentifiersRemoveRefSuffix, + }, + { + name: 'simplifyIdentifiersRenameRef', + generator: simplifyIdentifiersRenameRef, + }, +]; + +type MinimizeResult = + | {kind: 'success'} + | {kind: 'minimal'} + | {kind: 'minimized'; source: string}; + +/** + * Core minimization loop that attempts to reduce the input source code + * while preserving the compiler error. + */ +export function minimize( + input: string, + filename: string, + language: 'flow' | 'typescript', + sourceType: 'module' | 'script', + useRust: boolean = false, +): MinimizeResult { + // Load the compiler plugin + const pluginSrc = useRust ? BABEL_PLUGIN_RUST_SRC : BABEL_PLUGIN_SRC; + const importedCompilerPlugin = require(pluginSrc) as Record; + const BabelPluginReactCompiler = importedCompilerPlugin[ + 'default' + ] as PluginObj; + const parseConfigPragmaForTests = importedCompilerPlugin[ + PARSE_CONFIG_PRAGMA_IMPORT + ] as typeof ParseConfigPragma; + + // Get the initial error + const initialResult = compileAndGetError( + input, + filename, + language, + sourceType, + BabelPluginReactCompiler, + parseConfigPragmaForTests, + ); + + if (initialResult.kind === 'success') { + return {kind: 'success'}; + } + + if (initialResult.kind === 'parse_error') { + return {kind: 'success'}; + } + + const targetError = initialResult; + + // Parse the initial AST + let currentAst = parseInput(input, filename, language, sourceType); + let currentCode = input; + let changed = true; + let iterations = 0; + const maxIterations = 1000; // Safety limit + + process.stdout.write('\nMinimizing'); + + while (changed && iterations < maxIterations) { + changed = false; + iterations++; + + // Try each simplification strategy + for (const strategy of simplificationStrategies) { + const generator = strategy.generator(currentAst); + + for (const candidateAst of generator) { + let candidateCode: string; + try { + candidateCode = astToCode(candidateAst); + } catch { + // If code generation fails, skip this candidate + continue; + } + + const result = compileAndGetError( + candidateCode, + filename, + language, + sourceType, + BabelPluginReactCompiler, + parseConfigPragmaForTests, + ); + + if (errorsMatch(targetError, result)) { + // This simplification preserves the error, keep it + currentAst = candidateAst; + currentCode = candidateCode; + changed = true; + process.stdout.write('.'); + break; // Restart from the beginning with the new AST + } + } + + if (changed) { + break; // Restart the outer loop + } + } + } + + console.log('\n'); + + // Check if any minimization was achieved + if (currentCode === input) { + return {kind: 'minimal'}; + } + + return {kind: 'minimized', source: currentCode}; +} + +/** + * Compile code with a given plugin and return the output code (or error string). + */ +function compileAndGetOutput( + code: string, + filename: string, + language: 'flow' | 'typescript', + sourceType: 'module' | 'script', + plugin: PluginObj, + parseConfigPragmaFn: typeof ParseConfigPragma, +): string | null { + let ast: t.File; + try { + ast = parseInput(code, filename, language, sourceType); + } catch { + return null; + } + + const firstLine = code.substring(0, code.indexOf('\n')); + const config = parseConfigPragmaFn(firstLine, {compilationMode: 'all'}); + const options = { + ...config, + environment: { + ...config.environment, + }, + logger: { + logEvent: () => {}, + debugLogIRs: () => {}, + }, + enableReanimatedCheck: false, + }; + + try { + const result = transformFromAstSync(ast, code, { + filename: '/' + filename, + highlightCode: false, + retainLines: true, + compact: true, + plugins: [[plugin, options]], + sourceType: 'module', + ast: false, + cloneInputAst: true, + configFile: false, + babelrc: false, + }); + return result?.code ?? null; + } catch (e: unknown) { + return `ERROR: ${(e as Error).message}`; + } +} + +type MinimizeRustDeltaResult = + | {kind: 'no_delta'} + | {kind: 'minimal'} + | {kind: 'minimized'; source: string}; + +/** + * Core minimization loop that attempts to reduce the input source code + * while preserving a delta (difference in output) between the TS and Rust compilers. + */ +export function minimizeRustDelta( + input: string, + filename: string, + language: 'flow' | 'typescript', + sourceType: 'module' | 'script', +): MinimizeRustDeltaResult { + // Load both compiler plugins + const importedTsPlugin = require(BABEL_PLUGIN_SRC) as Record; + const importedRustPlugin = require(BABEL_PLUGIN_RUST_SRC) as Record< + string, + unknown + >; + const tsPlugin = importedTsPlugin['default'] as PluginObj; + const rustPlugin = importedRustPlugin['default'] as PluginObj; + const parseConfigPragmaForTests = importedTsPlugin[ + PARSE_CONFIG_PRAGMA_IMPORT + ] as typeof ParseConfigPragma; + + // Helper: check if TS and Rust outputs differ for given code + function hasDelta(code: string): boolean { + const tsOutput = compileAndGetOutput( + code, + filename, + language, + sourceType, + tsPlugin, + parseConfigPragmaForTests, + ); + const rustOutput = compileAndGetOutput( + code, + filename, + language, + sourceType, + rustPlugin, + parseConfigPragmaForTests, + ); + // Both null (e.g. parse error) means no delta + if (tsOutput == null && rustOutput == null) return false; + return tsOutput !== rustOutput; + } + + // Verify the initial input has a delta + if (!hasDelta(input)) { + return {kind: 'no_delta'}; + } + + // Parse the initial AST + let currentAst = parseInput(input, filename, language, sourceType); + let currentCode = input; + let changed = true; + let iterations = 0; + const maxIterations = 1000; + + process.stdout.write('\nMinimizing'); + + while (changed && iterations < maxIterations) { + changed = false; + iterations++; + + for (const strategy of simplificationStrategies) { + const generator = strategy.generator(currentAst); + + for (const candidateAst of generator) { + let candidateCode: string; + try { + candidateCode = astToCode(candidateAst); + } catch { + continue; + } + + if (hasDelta(candidateCode)) { + currentAst = candidateAst; + currentCode = candidateCode; + changed = true; + process.stdout.write('.'); + break; + } + } + + if (changed) { + break; + } + } + } + + console.log('\n'); + + if (currentCode === input) { + return {kind: 'minimal'}; + } + + return {kind: 'minimized', source: currentCode}; +} diff --git a/compiler/packages/snap/src/reporter.ts b/compiler/packages/snap/src/reporter.ts new file mode 100644 index 000000000000..412e4b523440 --- /dev/null +++ b/compiler/packages/snap/src/reporter.ts @@ -0,0 +1,275 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import chalk from 'chalk'; +import fs from 'fs'; +import invariant from 'invariant'; +import {diff} from 'jest-diff'; +import path from 'path'; + +function wrapWithTripleBackticks(s: string, ext: string | null = null): string { + return `\`\`\`${ext ?? ''} +${s} +\`\`\``; +} +const SPROUT_SEPARATOR = '\n### Eval output\n'; + +/** + * Normalize blank lines in the ## Code section of a snapshot. + * Strips blank lines that appear inside code blocks so that + * whitespace-only differences don't cause test failures. + */ +export function normalizeCodeBlankLines(snapshot: string): string { + const codeStart = snapshot.indexOf('## Code\n'); + if (codeStart === -1) return snapshot; + const codeBlockStart = snapshot.indexOf('```javascript\n', codeStart); + if (codeBlockStart === -1) return snapshot; + const contentStart = codeBlockStart + '```javascript\n'.length; + const codeBlockEnd = snapshot.indexOf('\n```', contentStart); + if (codeBlockEnd === -1) return snapshot; + + const before = snapshot.slice(0, contentStart); + const code = snapshot.slice(contentStart, codeBlockEnd); + const after = snapshot.slice(codeBlockEnd); + + const lines = code.split('\n'); + const filtered = lines.filter(line => { + if (line.trim() === '') return false; + // Strip unused var declarations from babel-plugin-idx (e.g., `var _ref2;`) + // These are generated by generateUidIdentifier and scope.push() in + // babel-plugin-idx, but the actual references may use a different _refN. + // The TS and Rust compilers interact differently with Babel's scope UID + // counter, producing different _refN numbering for unused declarations. + const match = line.match(/^\s*var (_ref\d*);$/); + if (match) { + const varName = match[1]; + // Check if this identifier is used anywhere else in the code + const regex = new RegExp('\\b' + varName + '\\b'); + const otherLines = lines.filter(l => l !== line); + const isUsed = otherLines.some(l => regex.test(l)); + if (!isUsed) return false; + } + return true; + }); + const normalized = filtered.join('\n'); + + return before + normalized + after; +} + +export function writeOutputToString( + input: string, + compilerOutput: string | null, + evaluatorOutput: string | null, + logs: string | null, + errorMessage: string | null, +) { + // leading newline intentional + let result = ` +## Input + +${wrapWithTripleBackticks(input, 'javascript')} +`; // trailing newline + space internional + + if (compilerOutput != null) { + result += ` +## Code + +${wrapWithTripleBackticks(compilerOutput, 'javascript')} +`; + } else { + result += '\n'; + } + + if (logs != null) { + result += ` +## Logs + +${wrapWithTripleBackticks(logs, null)} +`; + } + + if (errorMessage != null) { + result += ` +## Error + +${wrapWithTripleBackticks(errorMessage.replace(/^\/.*?:\s/, ''))} + \n`; + } + result += ` `; + if (evaluatorOutput != null) { + result += SPROUT_SEPARATOR + evaluatorOutput; + } + return result; +} + +export type TestResult = { + actual: string | null; // null == input did not exist + expected: string | null; // null == output did not exist + outputPath: string; + unexpectedError: string | null; +}; +export type TestResults = Map; + +/** + * Update the fixtures directory given the compilation results + */ +export async function update(results: TestResults): Promise { + let deleted = 0; + let updated = 0; + let created = 0; + const failed = []; + for (const [basename, result] of results) { + if (result.unexpectedError != null) { + console.log( + chalk.red.inverse.bold(' FAILED ') + ' ' + chalk.dim(basename), + ); + failed.push([basename, result.unexpectedError]); + } else if (result.actual == null) { + // Input was deleted but the expect file still existed, remove it + console.log( + chalk.red.inverse.bold(' REMOVE ') + ' ' + chalk.dim(basename), + ); + try { + fs.unlinkSync(result.outputPath); + console.log(' remove ' + result.outputPath); + deleted++; + } catch (e) { + console.error( + '[Snap tester error]: failed to remove ' + result.outputPath, + ); + failed.push([basename, result.unexpectedError]); + } + } else if (result.actual !== result.expected) { + // Expected output has changed + console.log( + chalk.blue.inverse.bold(' UPDATE ') + ' ' + chalk.dim(basename), + ); + try { + fs.writeFileSync(result.outputPath, result.actual, 'utf8'); + } catch (e) { + if (e?.code === 'ENOENT') { + // May have failed to create nested dir, so make a directory and retry + fs.mkdirSync(path.dirname(result.outputPath), {recursive: true}); + fs.writeFileSync(result.outputPath, result.actual, 'utf8'); + } + } + if (result.expected == null) { + created++; + } else { + updated++; + } + } else { + // Expected output is current + console.log( + chalk.green.inverse.bold(' OKAY ') + ' ' + chalk.dim(basename), + ); + } + } + console.log( + `${deleted} Deleted, ${created} Created, ${updated} Updated, ${failed.length} Failed`, + ); + for (const [basename, errorMsg] of failed) { + console.log(`${chalk.red.bold('Fail:')} ${basename}\n${errorMsg}`); + } +} + +/** + * Report test results to the user + * @returns boolean indicatig whether all tests passed + */ +// Fixtures where TS and Rust produce different output. Snapshots reflect Rust +// output (source of truth). Skipped when running the TS compiler. +const TS_SKIP_FIXTURES: Set = new Set([ + // Rust compiles successfully, TS would error. Renamed from error.todo-/error.bug-. + 'todo-hoist-type-alias-before-declaration', + // Error message/format divergences + 'fbt/error.todo-locally-require-fbt', + // Minor output difference (TS adds unused runtime import) + 'use-no-forget-multiple-with-eslint-suppression', + // Cosmetic blank-line/unused-var differences between Rust and TS codegen + 'debugger', + 'debugger-memoized', + 'idx-no-outlining', + 'optional-call-with-independently-memoizable-arg', +]); +export function report( + results: TestResults, + verbose: boolean = false, + rust: boolean = false, +): boolean { + const failures: Array<[string, TestResult]> = []; + for (const [basename, result] of results) { + if (!rust && TS_SKIP_FIXTURES.has(basename)) { + continue; + } + const actual = + rust && result.actual + ? normalizeCodeBlankLines(result.actual) + : result.actual; + const expected = + rust && result.expected + ? normalizeCodeBlankLines(result.expected) + : result.expected; + if (actual === expected && result.unexpectedError == null) { + if (verbose) { + console.log( + chalk.green.inverse.bold(' PASS ') + ' ' + chalk.dim(basename), + ); + } + } else { + if (verbose) { + console.log( + chalk.red.inverse.bold(' FAIL ') + ' ' + chalk.dim(basename), + ); + } + failures.push([basename, result]); + } + } + + if (failures.length !== 0) { + console.log('\n' + chalk.red.bold('Failures:') + '\n'); + + for (const [basename, result] of failures) { + console.log(chalk.red.bold('FAIL:') + ' ' + basename); + if (result.unexpectedError != null) { + console.log( + ` >> Unexpected error during test: \n${result.unexpectedError}`, + ); + } else { + const actual = + rust && result.actual + ? normalizeCodeBlankLines(result.actual) + : result.actual; + const expected = + rust && result.expected + ? normalizeCodeBlankLines(result.expected) + : result.expected; + if (expected == null) { + invariant(actual != null, '[Tester] Internal failure.'); + console.log( + chalk.red('[ expected fixture output is absent ]') + '\n', + ); + } else if (actual == null) { + invariant(expected != null, '[Tester] Internal failure.'); + console.log( + chalk.red(`[ fixture input for ${result.outputPath} is absent ]`) + + '\n', + ); + } else { + console.log(diff(expected, actual) + '\n'); + } + } + } + } + + console.log( + `${results.size} Tests, ${results.size - failures.length} Passed, ${ + failures.length + } Failed`, + ); + return failures.length === 0; +} diff --git a/compiler/packages/snap/src/runner-watch.ts b/compiler/packages/snap/src/runner-watch.ts new file mode 100644 index 000000000000..65abaabed9f6 --- /dev/null +++ b/compiler/packages/snap/src/runner-watch.ts @@ -0,0 +1,537 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import watcher from '@parcel/watcher'; +import path from 'path'; +import ts from 'typescript'; +import { + FIXTURES_PATH, + BABEL_PLUGIN_ROOT, + BABEL_PLUGIN_RUST_ROOT, + CRATES_PATH, +} from './constants'; +import {TestFilter, getFixtures} from './fixture-utils'; +import {execSync} from 'child_process'; +import fs from 'fs'; + +export function watchSrc( + onStart: () => void, + onComplete: (isSuccess: boolean) => void, +): ts.WatchOfConfigFile { + const configPath = ts.findConfigFile( + /*searchPath*/ BABEL_PLUGIN_ROOT, + ts.sys.fileExists, + 'tsconfig.json', + ); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + const createProgram = ts.createSemanticDiagnosticsBuilderProgram; + const host = ts.createWatchCompilerHost( + configPath, + undefined, + ts.sys, + createProgram, + () => {}, // we manually report errors in afterProgramCreate + () => {}, // we manually report watch status + ); + + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames, options, host, oldProgram) => { + onStart(); + return origCreateProgram(rootNames, options, host, oldProgram); + }; + host.afterProgramCreate = program => { + /** + * Avoid calling original postProgramCreate because it always emits tsc + * compilation output + */ + + // syntactic diagnostics refer to javascript syntax + const errors = program + .getSyntacticDiagnostics() + .filter(diag => diag.category === ts.DiagnosticCategory.Error); + // semantic diagnostics refer to typescript semantics + errors.push( + ...program + .getSemanticDiagnostics() + .filter(diag => diag.category === ts.DiagnosticCategory.Error), + ); + + if (errors.length > 0) { + for (const diagnostic of errors) { + let fileLoc: string; + if (diagnostic.file) { + // https://github.com/microsoft/TypeScript/blob/ddd5084659c423f4003d2176e12d879b6a5bcf30/src/compiler/program.ts#L663-L674 + const {line, character} = ts.getLineAndCharacterOfPosition( + diagnostic.file, + diagnostic.start!, + ); + const fileName = path.relative( + ts.sys.getCurrentDirectory(), + diagnostic.file.fileName, + ); + fileLoc = `${fileName}:${line + 1}:${character + 1} - `; + } else { + fileLoc = ''; + } + console.error( + `${fileLoc}error TS${diagnostic.code}:`, + ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'), + ); + } + console.error( + `Compilation failed (${errors.length} ${ + errors.length > 1 ? 'errors' : 'error' + }).\n`, + ); + } + + const isSuccess = errors.length === 0; + onComplete(isSuccess); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates + // the program over time. + return ts.createWatchProgram(host); +} + +/** + * Watch mode helpers + */ +export enum RunnerAction { + Test = 'Test', + Update = 'Update', +} + +type RunnerMode = { + action: RunnerAction; + filter: boolean; +}; + +export type RunnerState = { + // Monotonically increasing integer to describe the 'version' of the compiler. + // This is passed to `compile()` when compiling, so that the worker knows when + // to reset its module cache (compared to using its cached compiler version) + compilerVersion: number; + isCompilerBuildValid: boolean; + // timestamp of the last update + lastUpdate: number; + mode: RunnerMode; + filter: TestFilter | null; + debug: boolean; + // Input mode for interactive pattern entry + inputMode: 'none' | 'pattern'; + inputBuffer: string; + // Autocomplete state + allFixtureNames: Array; + matchingFixtures: Array; + selectedIndex: number; + // Track last run status of each fixture (for autocomplete suggestions) + fixtureLastRunStatus: Map; +}; + +function subscribeFixtures( + state: RunnerState, + onChange: (state: RunnerState) => void, +) { + // Watch the fixtures directory for changes + watcher.subscribe(FIXTURES_PATH, async (err, _events) => { + if (err) { + console.error(err); + process.exit(1); + } + // Try to ignore changes that occurred as a result of our explicitly updating + // fixtures in update(). + // Currently keeps a timestamp of last known changes, and ignore events that occurred + // around that timestamp. + const isRealUpdate = performance.now() - state.lastUpdate > 5000; + if (isRealUpdate) { + // Fixtures changed, re-run tests + state.mode.action = RunnerAction.Test; + onChange(state); + } + }); +} + +function subscribeTsc( + state: RunnerState, + onChange: (state: RunnerState) => void, + enableRust: boolean = false, +) { + // Run TS in incremental watch mode + watchSrc( + function onStart() { + // Notify the user when compilation starts but don't clear the screen yet + console.log('\nCompiling...'); + }, + isTypecheckSuccess => { + let isCompilerBuildValid = false; + if (isTypecheckSuccess) { + try { + execSync('yarn build', {cwd: BABEL_PLUGIN_ROOT}); + console.log('Built compiler successfully with tsup'); + isCompilerBuildValid = true; + } catch (e) { + console.warn('Failed to build compiler with tsup:', e); + } + } + // When using Rust, also build the Rust compiler after TS build succeeds + if (isCompilerBuildValid && enableRust) { + isCompilerBuildValid = buildRust(); + } + // Bump the compiler version after a build finishes + // and re-run tests + if (isCompilerBuildValid) { + state.compilerVersion++; + } + state.isCompilerBuildValid = isCompilerBuildValid; + state.mode.action = RunnerAction.Test; + onChange(state); + }, + ); +} + +export function buildRust(): boolean { + const compilerRoot = path.join(BABEL_PLUGIN_ROOT, '..', '..'); + try { + execSync('cargo build -p react_compiler_napi', { + cwd: compilerRoot, + stdio: 'inherit', + }); + } catch (e) { + console.error('Failed to build Rust compiler with cargo:', e); + return false; + } + + // Copy the built native module to the babel plugin package + const platform = process.platform; + const ext = platform === 'darwin' ? 'dylib' : 'so'; + const libName = + platform === 'darwin' + ? 'libreact_compiler_napi.dylib' + : 'libreact_compiler_napi.so'; + const sourcePath = path.join(compilerRoot, 'target', 'debug', libName); + const destPath = path.join(BABEL_PLUGIN_RUST_ROOT, 'native', 'index.node'); + + try { + fs.copyFileSync(sourcePath, destPath); + } catch (e) { + console.error( + `Failed to copy native module (${sourcePath} -> ${destPath}):`, + e, + ); + return false; + } + + // Build the TypeScript wrapper + try { + execSync('yarn build', {cwd: BABEL_PLUGIN_RUST_ROOT, stdio: 'inherit'}); + console.log('Built Rust compiler successfully'); + } catch (e) { + console.error('Failed to build Rust babel plugin with tsc:', e); + return false; + } + + return true; +} + +function subscribeRustCrates( + state: RunnerState, + onChange: (state: RunnerState) => void, +) { + watcher.subscribe(CRATES_PATH, async (err, events) => { + if (err) { + console.error(err); + process.exit(1); + } + // Only rebuild on .rs file changes + const hasRustChanges = events.some(e => e.path.endsWith('.rs')); + if (!hasRustChanges) { + return; + } + console.log('\nRust source changed, rebuilding...'); + if (buildRust()) { + state.compilerVersion++; + state.isCompilerBuildValid = true; + state.mode.action = RunnerAction.Test; + onChange(state); + } else { + state.isCompilerBuildValid = false; + console.error('Rust build failed, waiting for changes...'); + } + }); +} + +/** + * Levenshtein edit distance between two strings + */ +function editDistance(a: string, b: string): number { + const m = a.length; + const n = b.length; + + // Create a 2D array for memoization + const dp: number[][] = Array.from({length: m + 1}, () => + Array(n + 1).fill(0), + ); + + // Base cases + for (let i = 0; i <= m; i++) dp[i][0] = i; + for (let j = 0; j <= n; j++) dp[0][j] = j; + + // Fill in the rest + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + if (a[i - 1] === b[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]); + } + } + } + + return dp[m][n]; +} + +function filterFixtures( + allNames: Array, + pattern: string, +): Array { + if (pattern === '') { + return allNames; + } + const lowerPattern = pattern.toLowerCase(); + const matches = allNames.filter(name => + name.toLowerCase().includes(lowerPattern), + ); + // Sort by edit distance (lower = better match) + matches.sort((a, b) => { + const distA = editDistance(lowerPattern, a.toLowerCase()); + const distB = editDistance(lowerPattern, b.toLowerCase()); + return distA - distB; + }); + return matches; +} + +const MAX_DISPLAY = 15; + +function renderAutocomplete(state: RunnerState): void { + // Clear terminal + console.log('\u001Bc'); + + // Show current input + console.log(`Pattern: ${state.inputBuffer}`); + console.log(''); + + // Get current filter pattern if active + const currentFilterPattern = + state.mode.filter && state.filter ? state.filter.paths[0] : null; + + // Show matching fixtures (limit to MAX_DISPLAY) + const toShow = state.matchingFixtures.slice(0, MAX_DISPLAY); + + toShow.forEach((name, i) => { + const isSelected = i === state.selectedIndex; + const matchesCurrentFilter = + currentFilterPattern != null && + name.toLowerCase().includes(currentFilterPattern.toLowerCase()); + + let prefix: string; + if (isSelected) { + prefix = '> '; + } else if (matchesCurrentFilter) { + prefix = '* '; + } else { + prefix = ' '; + } + console.log(`${prefix}${name}`); + }); + + if (state.matchingFixtures.length > MAX_DISPLAY) { + console.log( + ` ... and ${state.matchingFixtures.length - MAX_DISPLAY} more`, + ); + } + + console.log(''); + console.log('โ†‘/โ†“/Tab navigate | Enter select | Esc cancel'); +} + +function subscribeKeyEvents( + state: RunnerState, + onChange: (state: RunnerState) => void, +) { + process.stdin.on('keypress', async (str, key) => { + // Handle input mode (pattern entry with autocomplete) + if (state.inputMode !== 'none') { + if (key.name === 'return') { + // Enter pressed - use selected fixture or typed text + let pattern: string; + if ( + state.selectedIndex >= 0 && + state.selectedIndex < state.matchingFixtures.length + ) { + pattern = state.matchingFixtures[state.selectedIndex]; + } else { + pattern = state.inputBuffer.trim(); + } + + state.inputMode = 'none'; + state.inputBuffer = ''; + state.allFixtureNames = []; + state.matchingFixtures = []; + state.selectedIndex = -1; + + if (pattern !== '') { + state.filter = {paths: [pattern]}; + state.mode.filter = true; + state.mode.action = RunnerAction.Test; + onChange(state); + } + return; + } else if (key.name === 'escape') { + // Cancel input mode + state.inputMode = 'none'; + state.inputBuffer = ''; + state.allFixtureNames = []; + state.matchingFixtures = []; + state.selectedIndex = -1; + // Redraw normal UI + onChange(state); + return; + } else if (key.name === 'up' || (key.name === 'tab' && key.shift)) { + // Navigate up in autocomplete list + if (state.matchingFixtures.length > 0) { + if (state.selectedIndex <= 0) { + state.selectedIndex = + Math.min(state.matchingFixtures.length, MAX_DISPLAY) - 1; + } else { + state.selectedIndex--; + } + renderAutocomplete(state); + } + return; + } else if (key.name === 'down' || (key.name === 'tab' && !key.shift)) { + // Navigate down in autocomplete list + if (state.matchingFixtures.length > 0) { + const maxIndex = + Math.min(state.matchingFixtures.length, MAX_DISPLAY) - 1; + if (state.selectedIndex >= maxIndex) { + state.selectedIndex = 0; + } else { + state.selectedIndex++; + } + renderAutocomplete(state); + } + return; + } else if (key.name === 'backspace') { + if (state.inputBuffer.length > 0) { + state.inputBuffer = state.inputBuffer.slice(0, -1); + state.matchingFixtures = filterFixtures( + state.allFixtureNames, + state.inputBuffer, + ); + state.selectedIndex = -1; + renderAutocomplete(state); + } + return; + } else if (str && !key.ctrl && !key.meta) { + // Regular character - accumulate, filter, and render + state.inputBuffer += str; + state.matchingFixtures = filterFixtures( + state.allFixtureNames, + state.inputBuffer, + ); + state.selectedIndex = -1; + renderAutocomplete(state); + return; + } + return; // Ignore other keys in input mode + } + + // Normal mode keypress handling + if (key.name === 'u') { + // u => update fixtures + state.mode.action = RunnerAction.Update; + } else if (key.name === 'q') { + process.exit(0); + } else if (key.name === 'a') { + // a => exit filter mode and run all tests + state.mode.filter = false; + state.filter = null; + state.mode.action = RunnerAction.Test; + } else if (key.name === 'd') { + // d => toggle debug logging + state.debug = !state.debug; + state.mode.action = RunnerAction.Test; + } else if (key.name === 'p') { + // p => enter pattern input mode with autocomplete + state.inputMode = 'pattern'; + state.inputBuffer = ''; + + // Load all fixtures for autocomplete + const fixtures = await getFixtures(null); + state.allFixtureNames = Array.from(fixtures.keys()).sort(); + // Show failed fixtures first when no pattern entered + const failedFixtures = Array.from(state.fixtureLastRunStatus.entries()) + .filter(([_, status]) => status === 'fail') + .map(([name]) => name) + .sort(); + state.matchingFixtures = + failedFixtures.length > 0 ? failedFixtures : state.allFixtureNames; + state.selectedIndex = -1; + + renderAutocomplete(state); + return; // Don't trigger onChange yet + } else { + // any other key re-runs tests + state.mode.action = RunnerAction.Test; + } + onChange(state); + }); +} + +export async function makeWatchRunner( + onChange: (state: RunnerState) => void, + debugMode: boolean, + initialPattern?: string, + enableRust: boolean = false, +): Promise { + // Determine initial filter state + let filter: TestFilter | null = null; + let filterEnabled = false; + + if (initialPattern) { + filter = {paths: [initialPattern]}; + filterEnabled = true; + } + + const state: RunnerState = { + compilerVersion: 0, + isCompilerBuildValid: false, + lastUpdate: -1, + mode: { + action: RunnerAction.Test, + filter: filterEnabled, + }, + filter, + debug: debugMode, + inputMode: 'none', + inputBuffer: '', + allFixtureNames: [], + matchingFixtures: [], + selectedIndex: -1, + fixtureLastRunStatus: new Map(), + }; + + subscribeTsc(state, onChange, enableRust); + subscribeFixtures(state, onChange); + subscribeKeyEvents(state, onChange); + if (enableRust) { + subscribeRustCrates(state, onChange); + } +} diff --git a/compiler/packages/snap/src/runner-worker.ts b/compiler/packages/snap/src/runner-worker.ts new file mode 100644 index 000000000000..7c4077bf2cef --- /dev/null +++ b/compiler/packages/snap/src/runner-worker.ts @@ -0,0 +1,251 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {PluginObj} from '@babel/core'; +import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/Utils/TestUtils'; +import type {printFunctionWithOutlined as PrintFunctionWithOutlined} from 'babel-plugin-react-compiler/src/HIR/PrintHIR'; +import type {printReactiveFunctionWithOutlined as PrintReactiveFunctionWithOutlined} from 'babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction'; +import {TransformResult, transformFixtureInput} from './compiler'; +import { + PARSE_CONFIG_PRAGMA_IMPORT, + PRINT_HIR_IMPORT, + PRINT_REACTIVE_IR_IMPORT, + BABEL_PLUGIN_SRC, + BABEL_PLUGIN_RUST_SRC, +} from './constants'; +import {TestFixture, getBasename, isExpectError} from './fixture-utils'; +import {TestResult, writeOutputToString} from './reporter'; +import {runSprout} from './sprout'; +import type { + CompilerPipelineValue, + Effect, + ValueKind, + ValueReason, +} from 'babel-plugin-react-compiler/src'; +import chalk from 'chalk'; + +const originalConsoleError = console.error; + +// Try to avoid clearing the entire require cache, which (as of this PR) +// contains ~1250 files. This assumes that no dependencies have global caches +// that may need to be invalidated across Forget reloads. +const invalidationSubpath = 'packages/babel-plugin-react-compiler/dist'; +const rustInvalidationSubpath = + 'packages/babel-plugin-react-compiler-rust/dist'; +let version: number | null = null; +export function clearRequireCache() { + Object.keys(require.cache).forEach(function (path) { + if ( + path.includes(invalidationSubpath) || + path.includes(rustInvalidationSubpath) + ) { + delete require.cache[path]; + } + }); +} + +async function compile( + input: string, + fixturePath: string, + compilerVersion: number, + shouldLog: boolean, + includeEvaluator: boolean, + enableRust: boolean = false, +): Promise<{ + error: string | null; + compileResult: TransformResult | null; +}> { + const seenConsoleErrors: Array = []; + console.error = (...messages: Array) => { + seenConsoleErrors.push(...messages); + }; + if (version !== null && compilerVersion !== version) { + clearRequireCache(); + } + version = compilerVersion; + + let compileResult: TransformResult | null = null; + let error: string | null = null; + try { + // Always load TS compiler for utilities (parseConfigPragmaForTests, print functions) + const importedCompilerPlugin = require(BABEL_PLUGIN_SRC) as Record< + string, + unknown + >; + + // Load the appropriate babel plugin + const pluginSrc = enableRust ? BABEL_PLUGIN_RUST_SRC : BABEL_PLUGIN_SRC; + const importedPlugin = enableRust + ? (require(pluginSrc) as Record) + : importedCompilerPlugin; + + // NOTE: we intentionally require lazily here so that we can clear the require cache + // and load fresh versions of the compiler when `compilerVersion` changes. + const BabelPluginReactCompiler = importedPlugin['default'] as PluginObj; + const EffectEnum = importedCompilerPlugin['Effect'] as typeof Effect; + const ValueKindEnum = importedCompilerPlugin[ + 'ValueKind' + ] as typeof ValueKind; + const ValueReasonEnum = importedCompilerPlugin[ + 'ValueReason' + ] as typeof ValueReason; + const printFunctionWithOutlined = importedCompilerPlugin[ + PRINT_HIR_IMPORT + ] as typeof PrintFunctionWithOutlined; + const printReactiveFunctionWithOutlined = importedCompilerPlugin[ + PRINT_REACTIVE_IR_IMPORT + ] as typeof PrintReactiveFunctionWithOutlined; + const parseConfigPragmaForTests = importedCompilerPlugin[ + PARSE_CONFIG_PRAGMA_IMPORT + ] as typeof ParseConfigPragma; + + let lastLogged: string | null = null; + const debugIRLogger = shouldLog + ? (value: CompilerPipelineValue) => { + let printed: string; + switch (value.kind) { + case 'hir': + printed = printFunctionWithOutlined(value.value); + break; + case 'reactive': + printed = printReactiveFunctionWithOutlined(value.value); + break; + case 'debug': + printed = value.value; + break; + case 'ast': + // skip printing ast as we already write fixture output JS + printed = '(ast)'; + break; + } + + if (printed !== lastLogged) { + lastLogged = printed; + console.log(`${chalk.green(value.name)}:\n ${printed}\n`); + } else { + console.log(`${chalk.blue(value.name)}: (no change)\n`); + } + } + : () => {}; + + // only try logging if we filtered out all but one fixture, + // since console log order is non-deterministic + const result = await transformFixtureInput( + input, + fixturePath, + parseConfigPragmaForTests, + BabelPluginReactCompiler, + includeEvaluator, + debugIRLogger, + EffectEnum, + ValueKindEnum, + ValueReasonEnum, + ); + + if (result.kind === 'err') { + error = result.msg; + } else { + compileResult = result.value; + } + } catch (e) { + if (shouldLog) { + console.error(e.stack); + } + error = e.message.replace(/\u001b[^m]*m/g, ''); + } + + // Promote console errors so they can be recorded in fixture output + for (const consoleError of seenConsoleErrors) { + if (error != null) { + error = `${error}\n\n${consoleError}`; + } else { + error = `ConsoleError: ${consoleError}`; + } + } + console.error = originalConsoleError; + + return { + error, + compileResult, + }; +} + +export async function transformFixture( + fixture: TestFixture, + compilerVersion: number, + shouldLog: boolean, + includeEvaluator: boolean, + enableRust: boolean = false, +): Promise { + const {input, snapshot: expected, snapshotPath: outputPath} = fixture; + const basename = getBasename(fixture); + const expectError = isExpectError(fixture); + + // Input will be null if the input file did not exist, in which case the output file + // is stale + if (input === null) { + return { + outputPath, + actual: null, + expected, + unexpectedError: null, + }; + } + const {compileResult, error} = await compile( + input, + fixture.fixturePath, + compilerVersion, + shouldLog, + includeEvaluator, + enableRust, + ); + + let unexpectedError: string | null = null; + if (expectError) { + if (error === null) { + unexpectedError = `Expected an error to be thrown for fixture: \`${basename}\`, remove the 'error.' prefix if an error is not expected.`; + } + } else { + if (error !== null) { + unexpectedError = `Expected fixture \`${basename}\` to succeed but it failed with error:\n\n${error}`; + } else if (compileResult == null) { + unexpectedError = `Expected output for fixture \`${basename}\`.`; + } + } + + const snapOutput: string | null = compileResult?.forgetOutput ?? null; + let sproutOutput: string | null = null; + if (compileResult?.evaluatorCode != null) { + const sproutResult = runSprout( + compileResult.evaluatorCode.original, + compileResult.evaluatorCode.forget, + ); + if (sproutResult.kind === 'invalid') { + unexpectedError ??= ''; + unexpectedError += `\n\n${sproutResult.value}`; + } else { + sproutOutput = sproutResult.value; + } + } else if (!includeEvaluator && expected != null) { + sproutOutput = expected.split('\n### Eval output\n')[1]; + } + + const actualOutput = writeOutputToString( + input, + snapOutput, + sproutOutput, + compileResult?.logs ?? null, + error, + ); + + return { + outputPath, + actual: actualOutput, + expected, + unexpectedError, + }; +} diff --git a/compiler/packages/snap/src/runner.ts b/compiler/packages/snap/src/runner.ts new file mode 100644 index 000000000000..1ef66229fdb6 --- /dev/null +++ b/compiler/packages/snap/src/runner.ts @@ -0,0 +1,673 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {Worker} from 'jest-worker'; +import {cpus} from 'os'; +import process from 'process'; +import * as readline from 'readline'; +import ts from 'typescript'; +import yargs from 'yargs'; +import {hideBin} from 'yargs/helpers'; +import {BABEL_PLUGIN_ROOT, PROJECT_ROOT} from './constants'; +import {TestFilter, getFixtures} from './fixture-utils'; +import { + TestResult, + TestResults, + normalizeCodeBlankLines, + report, + update, +} from './reporter'; +import { + RunnerAction, + RunnerState, + buildRust, + makeWatchRunner, + watchSrc, +} from './runner-watch'; +import * as runnerWorker from './runner-worker'; +import {execSync} from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import {minimize, minimizeRustDelta} from './minimize'; +import {parseInput, parseLanguage, parseSourceType} from './compiler'; +import { + PARSE_CONFIG_PRAGMA_IMPORT, + PRINT_HIR_IMPORT, + PRINT_REACTIVE_IR_IMPORT, + BABEL_PLUGIN_SRC, +} from './constants'; +import chalk from 'chalk'; + +const WORKER_PATH = require.resolve('./runner-worker.js'); +const NUM_WORKERS = cpus().length - 1; + +readline.emitKeypressEvents(process.stdin); + +type TestOptions = { + sync: boolean; + workerThreads: boolean; + watch: boolean; + update: boolean; + pattern?: string; + debug: boolean; + verbose: boolean; + rust: boolean; +}; + +type MinimizeOptions = { + path: string; + update: boolean; + rust: boolean; +}; + +type MinimizeRustDeltaOptions = { + path: string; + update: boolean; +}; + +type CompileOptions = { + path: string; + debug: boolean; +}; + +async function runTestCommand(opts: TestOptions): Promise { + // Rust native module doesn't load in jest-worker child processes, + // so force sync mode when using the Rust backend. + if (opts.rust) { + opts.sync = true; + } + + const worker: Worker & typeof runnerWorker = new Worker(WORKER_PATH, { + enableWorkerThreads: opts.workerThreads, + numWorkers: NUM_WORKERS, + }) as any; + worker.getStderr().pipe(process.stderr); + worker.getStdout().pipe(process.stdout); + + // Check if watch mode should be enabled + const shouldWatch = opts.watch; + + if (shouldWatch) { + makeWatchRunner( + state => onChange(worker, state, opts.sync, opts.verbose, opts.rust), + opts.debug, + opts.pattern, + opts.rust, + ); + if (opts.pattern) { + /** + * Warm up wormers when in watch mode. Loading the Forget babel plugin + * and all of its transitive dependencies takes 1-3s (per worker) on a M1. + * As jest-worker dispatches tasks using a round-robin strategy, we can + * avoid an additional 1-3s wait on the first num_workers runs by warming + * up workers eagerly. + */ + for (let i = 0; i < NUM_WORKERS - 1; i++) { + worker.transformFixture( + { + fixturePath: 'tmp', + snapshotPath: './tmp.expect.md', + inputPath: './tmp.js', + input: ` + function Foo(props) { + return identity(props); + } + `, + snapshot: null, + }, + 0, + false, + false, + opts.rust, + ); + } + } + } else { + // Non-watch mode. For simplicity we re-use the same watchSrc() function. + // After the first build completes run tests and exit + const tsWatch: ts.WatchOfConfigFile = + watchSrc( + () => {}, + async (isTypecheckSuccess: boolean) => { + let isSuccess = false; + if (!isTypecheckSuccess) { + console.error( + 'Found typescript errors in Forget source code, skipping test fixtures.', + ); + } else { + try { + execSync('yarn build', {cwd: BABEL_PLUGIN_ROOT}); + console.log('Built compiler successfully with tsup'); + + if (opts.rust && !buildRust()) { + throw new Error('Failed to build Rust compiler'); + } + + // Determine which filter to use + let testFilter: TestFilter | null = null; + if (opts.pattern) { + testFilter = { + paths: [opts.pattern], + }; + } + + const results = await runFixtures( + worker, + testFilter, + 0, + opts.debug, + false, // no requireSingleFixture in non-watch mode + opts.sync, + opts.rust, + ); + if (opts.update) { + update(results); + isSuccess = true; + } else { + isSuccess = report(results, opts.verbose, opts.rust); + } + } catch (e) { + console.warn('Failed to build compiler with tsup:', e); + } + } + tsWatch?.close(); + await worker.end(); + process.exit(isSuccess ? 0 : 1); + }, + ); + } +} + +async function runMinimizeCommand(opts: MinimizeOptions): Promise { + // Resolve the input path + const inputPath = path.isAbsolute(opts.path) + ? opts.path + : path.resolve(PROJECT_ROOT, opts.path); + + // Check if file exists + if (!fs.existsSync(inputPath)) { + console.error(`Error: File not found: ${inputPath}`); + process.exit(1); + } + + // Read the input file + const input = fs.readFileSync(inputPath, 'utf-8'); + const filename = path.basename(inputPath); + const firstLine = input.substring(0, input.indexOf('\n')); + const language = parseLanguage(firstLine); + const sourceType = parseSourceType(firstLine); + + if (opts.rust && !buildRust()) { + console.error('Error: Failed to build Rust compiler'); + process.exit(1); + } + + console.log( + `Minimizing: ${inputPath}${opts.rust ? ' (using Rust compiler)' : ''}`, + ); + + const originalLines = input.split('\n').length; + + // Run the minimization + const result = minimize(input, filename, language, sourceType, opts.rust); + + if (result.kind === 'success') { + console.log('Could not minimize: the input compiles successfully.'); + process.exit(0); + } + + if (result.kind === 'minimal') { + console.log( + 'Could not minimize: the input fails but is already minimal and cannot be reduced further.', + ); + process.exit(0); + } + + // Output the minimized code + console.log('--- Minimized Code ---'); + console.log(result.source); + + const minimizedLines = result.source.split('\n').length; + console.log( + `\nReduced from ${originalLines} lines to ${minimizedLines} lines`, + ); + + if (opts.update) { + fs.writeFileSync(inputPath, result.source, 'utf-8'); + console.log(`\nUpdated ${inputPath} with minimized code.`); + } +} + +async function runMinimizeRustDeltaCommand( + opts: MinimizeRustDeltaOptions, +): Promise { + const inputPath = path.isAbsolute(opts.path) + ? opts.path + : path.resolve(PROJECT_ROOT, opts.path); + + if (!fs.existsSync(inputPath)) { + console.error(`Error: File not found: ${inputPath}`); + process.exit(1); + } + + // Build both compilers + execSync('yarn build', {cwd: BABEL_PLUGIN_ROOT}); + if (!buildRust()) { + console.error('Error: Failed to build Rust compiler'); + process.exit(1); + } + + const input = fs.readFileSync(inputPath, 'utf-8'); + const filename = path.basename(inputPath); + const firstLine = input.substring(0, input.indexOf('\n')); + const language = parseLanguage(firstLine); + const sourceType = parseSourceType(firstLine); + + console.log(`Minimizing TS/Rust delta: ${inputPath}`); + + const originalLines = input.split('\n').length; + + const result = minimizeRustDelta(input, filename, language, sourceType); + + if (result.kind === 'no_delta') { + console.log( + 'Could not minimize: TS and Rust compilers produce the same output.', + ); + process.exit(0); + } + + if (result.kind === 'minimal') { + console.log( + 'Could not minimize: the delta exists but the input is already minimal.', + ); + process.exit(0); + } + + console.log('--- Minimized Code ---'); + console.log(result.source); + + const minimizedLines = result.source.split('\n').length; + console.log( + `\nReduced from ${originalLines} lines to ${minimizedLines} lines`, + ); + + if (opts.update) { + fs.writeFileSync(inputPath, result.source, 'utf-8'); + console.log(`\nUpdated ${inputPath} with minimized code.`); + } +} + +async function runCompileCommand(opts: CompileOptions): Promise { + // Resolve the input path + const inputPath = path.isAbsolute(opts.path) + ? opts.path + : path.resolve(PROJECT_ROOT, opts.path); + + // Check if file exists + if (!fs.existsSync(inputPath)) { + console.error(`Error: File not found: ${inputPath}`); + process.exit(1); + } + + // Read the input file + const input = fs.readFileSync(inputPath, 'utf-8'); + const filename = path.basename(inputPath); + const firstLine = input.substring(0, input.indexOf('\n')); + const language = parseLanguage(firstLine); + const sourceType = parseSourceType(firstLine); + + // Import the compiler + const importedCompilerPlugin = require(BABEL_PLUGIN_SRC) as Record< + string, + any + >; + const BabelPluginReactCompiler = importedCompilerPlugin['default']; + const parseConfigPragmaForTests = + importedCompilerPlugin[PARSE_CONFIG_PRAGMA_IMPORT]; + const printFunctionWithOutlined = importedCompilerPlugin[PRINT_HIR_IMPORT]; + const printReactiveFunctionWithOutlined = + importedCompilerPlugin[PRINT_REACTIVE_IR_IMPORT]; + const EffectEnum = importedCompilerPlugin['Effect']; + const ValueKindEnum = importedCompilerPlugin['ValueKind']; + const ValueReasonEnum = importedCompilerPlugin['ValueReason']; + + // Setup debug logger + let lastLogged: string | null = null; + const debugIRLogger = opts.debug + ? (value: any) => { + let printed: string; + switch (value.kind) { + case 'hir': + printed = printFunctionWithOutlined(value.value); + break; + case 'reactive': + printed = printReactiveFunctionWithOutlined(value.value); + break; + case 'debug': + printed = value.value; + break; + case 'ast': + printed = '(ast)'; + break; + default: + printed = String(value); + } + + if (printed !== lastLogged) { + lastLogged = printed; + console.log(`${chalk.green(value.name)}:\n${printed}\n`); + } else { + console.log(`${chalk.blue(value.name)}: (no change)\n`); + } + } + : () => {}; + + // Parse the input + let ast; + try { + ast = parseInput(input, filename, language, sourceType); + } catch (e: any) { + console.error(`Parse error: ${e.message}`); + process.exit(1); + } + + // Build plugin options + const config = parseConfigPragmaForTests(firstLine, {compilationMode: 'all'}); + const options = { + ...config, + environment: { + ...config.environment, + }, + logger: { + logEvent: () => {}, + debugLogIRs: debugIRLogger, + }, + enableReanimatedCheck: false, + }; + + // Compile + const {transformFromAstSync} = require('@babel/core'); + try { + const result = transformFromAstSync(ast, input, { + filename: '/' + filename, + highlightCode: false, + retainLines: true, + compact: true, + plugins: [[BabelPluginReactCompiler, options]], + sourceType: 'module', + ast: false, + cloneInputAst: true, + configFile: false, + babelrc: false, + }); + + if (result?.code != null) { + // Format the output + const prettier = require('prettier'); + const formatted = await prettier.format(result.code, { + semi: true, + parser: language === 'typescript' ? 'babel-ts' : 'flow', + }); + console.log(formatted); + } else { + console.error('Error: No code emitted from compiler'); + process.exit(1); + } + } catch (e: any) { + console.error(e.message); + process.exit(1); + } +} + +yargs(hideBin(process.argv)) + .command( + ['test', '$0'], + 'Run compiler tests', + yargs => { + return yargs + .boolean('sync') + .describe( + 'sync', + 'Run compiler in main thread (instead of using worker threads or subprocesses). Defaults to false.', + ) + .default('sync', false) + .boolean('worker-threads') + .describe( + 'worker-threads', + 'Run compiler in worker threads (instead of subprocesses). Defaults to true.', + ) + .default('worker-threads', true) + .boolean('watch') + .describe( + 'watch', + 'Run compiler in watch mode, re-running after changes', + ) + .alias('w', 'watch') + .default('watch', false) + .boolean('update') + .alias('u', 'update') + .describe('update', 'Update fixtures') + .default('update', false) + .string('pattern') + .alias('p', 'pattern') + .describe( + 'pattern', + 'Optional glob pattern to filter fixtures (e.g., "error.*", "use-memo")', + ) + .boolean('debug') + .alias('d', 'debug') + .describe('debug', 'Enable debug logging to print HIR for each pass') + .default('debug', false) + .boolean('verbose') + .alias('v', 'verbose') + .describe('verbose', 'Print individual test results') + .default('verbose', false) + .boolean('rust') + .describe('rust', 'Use the Rust compiler backend instead of TypeScript') + .default('rust', false); + }, + async argv => { + await runTestCommand(argv as TestOptions); + }, + ) + .command( + 'minimize ', + 'Minimize a test case to reproduce a compiler error', + yargs => { + return yargs + .positional('path', { + describe: 'Path to the file to minimize', + type: 'string', + demandOption: true, + }) + .boolean('update') + .alias('u', 'update') + .describe( + 'update', + 'Update the input file in-place with the minimized version', + ) + .default('update', false) + .boolean('rust') + .describe('rust', 'Use the Rust compiler backend instead of TypeScript') + .default('rust', false); + }, + async argv => { + await runMinimizeCommand(argv as unknown as MinimizeOptions); + }, + ) + .command( + 'minimize-rust-delta ', + 'Minimize a test case to the smallest code that still produces different output between TS and Rust compilers', + yargs => { + return yargs + .positional('path', { + describe: 'Path to the file to minimize', + type: 'string', + demandOption: true, + }) + .boolean('update') + .alias('u', 'update') + .describe( + 'update', + 'Update the input file in-place with the minimized version', + ) + .default('update', false); + }, + async argv => { + await runMinimizeRustDeltaCommand( + argv as unknown as MinimizeRustDeltaOptions, + ); + }, + ) + .command( + 'compile ', + 'Compile a file with the React Compiler', + yargs => { + return yargs + .positional('path', { + describe: 'Path to the file to compile', + type: 'string', + demandOption: true, + }) + .boolean('debug') + .alias('d', 'debug') + .describe('debug', 'Enable debug logging to print HIR for each pass') + .default('debug', false); + }, + async argv => { + await runCompileCommand(argv as unknown as CompileOptions); + }, + ) + .help('help') + .strict() + .demandCommand() + .parse(); + +/** + * Do a test run and return the test results + */ +async function runFixtures( + worker: Worker & typeof runnerWorker, + filter: TestFilter | null, + compilerVersion: number, + debug: boolean, + requireSingleFixture: boolean, + sync: boolean, + enableRust: boolean = false, +): Promise { + // We could in theory be fancy about tracking the contents of the fixtures + // directory via our file subscription, but it's simpler to just re-read + // the directory each time. + const fixtures = await getFixtures(filter); + const isOnlyFixture = filter !== null && fixtures.size === 1; + const shouldLog = debug && (!requireSingleFixture || isOnlyFixture); + + let entries: Array<[string, TestResult]>; + if (!sync) { + // Note: promise.all to ensure parallelism when enabled + const work: Array> = []; + for (const [fixtureName, fixture] of fixtures) { + work.push( + worker + .transformFixture( + fixture, + compilerVersion, + shouldLog, + true, + enableRust, + ) + .then(result => [fixtureName, result]), + ); + } + + entries = await Promise.all(work); + } else { + entries = []; + for (const [fixtureName, fixture] of fixtures) { + let output = await runnerWorker.transformFixture( + fixture, + compilerVersion, + shouldLog, + true, + enableRust, + ); + entries.push([fixtureName, output]); + } + } + + return new Map(entries); +} + +// Callback to re-run tests after some change +async function onChange( + worker: Worker & typeof runnerWorker, + state: RunnerState, + sync: boolean, + verbose: boolean, + enableRust: boolean = false, +) { + const {compilerVersion, isCompilerBuildValid, mode, filter, debug} = state; + if (isCompilerBuildValid) { + const start = performance.now(); + + // console.clear() only works when stdout is connected to a TTY device. + // we're currently piping stdout (see main.ts), so let's do a 'hack' + console.log('\u001Bc'); + + // we don't clear console after this point, since + // it may contain debug console logging + const results = await runFixtures( + worker, + mode.filter ? filter : null, + compilerVersion, + debug, + true, // requireSingleFixture in watch mode + sync, + enableRust, + ); + const end = performance.now(); + + // Track fixture status for autocomplete suggestions + for (const [basename, result] of results) { + const actual = + enableRust && result.actual + ? normalizeCodeBlankLines(result.actual) + : result.actual; + const expected = + enableRust && result.expected + ? normalizeCodeBlankLines(result.expected) + : result.expected; + const failed = actual !== expected || result.unexpectedError != null; + state.fixtureLastRunStatus.set(basename, failed ? 'fail' : 'pass'); + } + + if (mode.action === RunnerAction.Update) { + update(results); + state.lastUpdate = end; + } else { + report(results, verbose, enableRust); + } + console.log(`Completed in ${Math.floor(end - start)} ms`); + } else { + console.error( + `${mode}: Found errors in Forget source code, skipping test fixtures.`, + ); + } + console.log( + '\n' + + (mode.filter + ? `Current mode = FILTER, pattern = "${filter?.paths[0] ?? ''}".` + : 'Current mode = NORMAL, run all test fixtures.') + + '\nWaiting for input or file changes...\n' + + 'u - update all fixtures\n' + + `d - toggle (turn ${debug ? 'off' : 'on'}) debug logging\n` + + 'p - enter pattern to filter fixtures\n' + + (mode.filter ? 'a - run all tests (exit filter mode)\n' : '') + + 'q - quit\n' + + '[any] - rerun tests\n', + ); +} diff --git a/compiler/packages/snap/src/sprout/README.md b/compiler/packages/snap/src/sprout/README.md new file mode 100644 index 000000000000..1499c2f71f6e --- /dev/null +++ b/compiler/packages/snap/src/sprout/README.md @@ -0,0 +1,80 @@ +## Sprout ๐ŸŒฑ +React Forget test framework that executes compiler fixtures. + +Currently, Sprout runs each fixture with a known set of inputs and annotations. Sprout compares execution outputs (i.e. return values and console logs) of original source code and the corresponding Forget-transformed version. +We hope to add fuzzing capabilities to Sprout, synthesizing sets of program inputs based on type and/or effect annotations. + +Sprout is now enabled for all fixtures! If Sprout cannot execute your fixture due to some technical limitations, add your fixture to [`SproutTodoFilter.ts`](./src/SproutTodoFilter.ts) with a comment explaining why. + +### Sprout CLI +Sprout is now run as a part of snap, except when in filter mode. + +### Adding fixtures to Sprout + +#### 1. Annotate fixtures. +Each fixture test executed by Sprout needs to export const `FIXTURE_ENTRYPOINT` object with the following type signature. + +```js +type FixtureEntrypoint = { + // function to be invoked + fn: ((...params: Array) => any), + // params to pass to fn + // (if `fn` is a react component, this should be an array + // with exactly one element -- props) + params: Array, +} +``` + +Example: +```js +// test.js +function MyComponent(props) { + return
{props.a + props.b}
; +} +export const FIXTURE_ENTRYPOINT = { + fn: MyComponent, + params: [{a: "hello ", b: "world"}], +}; +``` + +#### 2. Import / define helper functions. + +- Prefer importing helper functions for readability and simplicity. +- Fixtures that require helper functions with specific types or mutability can define their own within the same fixture file. + +```js +// test.js +import { addOne } from 'shared-runtime'; + +function customHelper(val1, val2) { + // This directive is important, as helper functions don't + // always follow the rules of React. + "use no forget"; + // ... +} + +// ... +``` + +#### Notes +- If your fixture needs to import from an external module, we currently only support importing from `react` (see Milestones todo list). + +- Any fixture can use React hooks, but they need to be first imported. We may later enforce that only `isComponent: true` fixtures can use React hooks. + ```ts + import {useState} from 'react'; + ``` + +- If your fixture wants to export multiple functions to Sprout to run, please split up the fixture into multiple files (e.g. `test-case-1`, `test-case-2`, etc). + +- Sprout currently runs each fixture in an iife to prevent variable collisions, but it does not run fixtures in isolation. Please do not mutate any external state in fixtures. + +- Sprout does not run fixtures listed in [`SproutTodoFilter.ts`](./src/SproutTodoFilter.ts), even in filter mode. + +### Milestones: +- [โœ…] Render fixtures with React runtime / `testing-library/react`. +- [โœ…] Make Sprout CLI -runnable and report results in process exit code. +- [โœ…] Enable Sprout by default and run it in the Github Actions pipeline. +- [๐Ÿšง] Make all existing test fixtures Sprout compatible (see `SproutTodoFilter.ts`). This involves each fixture being annotated with `FIXTURE_ENTRYPOINT` and using shared functions and/or defining its own helpers. + - 77 done, ~410 to go +- [โœ…] *(optional)* Store Sprout output as snapshot files. i.e. each fixture could have a `fixture.js`, `fixture.snap.md`, and `fixture.sprout.md`. +- [โœ…] Add support for `fbt`. diff --git a/compiler/packages/snap/src/sprout/ReactForgetFeatureFlag.ts b/compiler/packages/snap/src/sprout/ReactForgetFeatureFlag.ts new file mode 100644 index 000000000000..48b0abd18036 --- /dev/null +++ b/compiler/packages/snap/src/sprout/ReactForgetFeatureFlag.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export function isForgetEnabled_Fixtures(): boolean { + return true; +} diff --git a/compiler/packages/snap/src/sprout/evaluator.ts b/compiler/packages/snap/src/sprout/evaluator.ts new file mode 100644 index 000000000000..ba44f01b0aa3 --- /dev/null +++ b/compiler/packages/snap/src/sprout/evaluator.ts @@ -0,0 +1,310 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {render} from '@testing-library/react'; +import {JSDOM} from 'jsdom'; +import React, {MutableRefObject} from 'react'; +import util from 'util'; +import {z} from 'zod/v4'; +import {fromZodError} from 'zod-validation-error/v4'; +import {initFbt, toJSON} from './shared-runtime'; + +/** + * Set up the global environment for JSDOM tests. + * This is a hack to let us share code and setup between the test + * and runner environments. As an alternative, we could evaluate all setup + * in the jsdom test environment (which provides more isolation), but that + * may be slower. + */ +const {window: testWindow} = new JSDOM(undefined); +(globalThis as any).document = testWindow.document; +(globalThis as any).window = testWindow.window; +(globalThis as any).React = React; +(globalThis as any).render = render; +initFbt(); + +(globalThis as any).placeholderFn = function (..._args: Array) { + throw new Error('Fixture not implemented!'); +}; +export type EvaluatorResult = { + kind: 'ok' | 'exception' | 'UnexpectedError'; + value: string; + logs: Array; +}; + +/** + * Define types and schemas for fixture entrypoint + */ +const EntrypointSchema = z.strictObject({ + fn: z.union([z.function(), z.object({})]), + params: z.array(z.any()), + + // DEPRECATED, unused + isComponent: z.optional(z.boolean()), + + // if enabled, the `fn` is assumed to be a component and this is assumed + // to be an array of props. the component is mounted once and rendered + // once per set of props in this array. + sequentialRenders: z.optional(z.nullable(z.array(z.any()))).default(null), +}); +const ExportSchema = z.object({ + FIXTURE_ENTRYPOINT: EntrypointSchema, +}); + +const NO_ERROR_SENTINEL = Symbol(); +/** + * Wraps WrapperTestComponent in an error boundary to simplify re-rendering + * when an exception is thrown. + * A simpler alternative may be to re-mount test components manually. + */ +class WrapperTestComponentWithErrorBoundary extends React.Component< + {fn: any; params: Array}, + {errorFromLastRender: any} +> { + /** + * Limit retries of the child component by caching seen errors. + */ + propsErrorMap: Map; + lastProps: any | null; + // lastProps: object | null; + constructor(props: any) { + super(props); + this.lastProps = null; + this.propsErrorMap = new Map(); + this.state = { + errorFromLastRender: NO_ERROR_SENTINEL, + }; + } + static getDerivedStateFromError(error: any) { + // Reschedule a second render that immediately returns the cached error + return {errorFromLastRender: error}; + } + override componentDidUpdate() { + if (this.state.errorFromLastRender !== NO_ERROR_SENTINEL) { + // Reschedule a third render that immediately returns the cached error + this.setState({errorFromLastRender: NO_ERROR_SENTINEL}); + } + } + override render() { + if ( + this.state.errorFromLastRender !== NO_ERROR_SENTINEL && + this.props === this.lastProps + ) { + /** + * The last render errored, cache the error message to avoid running the + * test fixture more than once + */ + const errorMsg = `[[ (exception in render) ${this.state.errorFromLastRender?.toString()} ]]`; + this.propsErrorMap.set(this.lastProps, errorMsg); + return errorMsg; + } + this.lastProps = this.props; + const cachedError = this.propsErrorMap.get(this.props); + if (cachedError != null) { + return cachedError; + } + return React.createElement(WrapperTestComponent, this.props); + } +} + +function WrapperTestComponent(props: {fn: any; params: Array}) { + const result = props.fn(...props.params); + // Hacky solution to determine whether the fixture returned jsx (which + // needs to passed through to React's runtime as-is) or a non-jsx value + // (which should be converted to a string). + if (typeof result === 'object' && result != null && '$$typeof' in result) { + return result; + } else { + return toJSON(result); + } +} + +function renderComponentSequentiallyForEachProps( + fn: any, + sequentialRenders: Array, +): string { + if (sequentialRenders.length === 0) { + throw new Error( + 'Expected at least one set of props when using `sequentialRenders`', + ); + } + const initialProps = sequentialRenders[0]!; + const results = []; + const {rerender, container} = render( + React.createElement(WrapperTestComponentWithErrorBoundary, { + fn, + params: [initialProps], + }), + ); + results.push(container.innerHTML); + + for (let i = 1; i < sequentialRenders.length; i++) { + rerender( + React.createElement(WrapperTestComponentWithErrorBoundary, { + fn, + params: [sequentialRenders[i]], + }), + ); + results.push(container.innerHTML); + } + return results.join('\n'); +} + +type FixtureEvaluatorResult = Omit; +(globalThis as any).evaluateFixtureExport = function ( + exports: unknown, +): FixtureEvaluatorResult { + const parsedExportResult = ExportSchema.safeParse(exports); + if (!parsedExportResult.success) { + const exportDetail = + typeof exports === 'object' && exports != null + ? `object ${util.inspect(exports)}` + : `${exports}`; + return { + kind: 'UnexpectedError', + value: `${fromZodError(parsedExportResult.error)}\nFound ` + exportDetail, + }; + } + const entrypoint = parsedExportResult.data.FIXTURE_ENTRYPOINT; + if (entrypoint.sequentialRenders !== null) { + const result = renderComponentSequentiallyForEachProps( + entrypoint.fn, + entrypoint.sequentialRenders, + ); + + return { + kind: 'ok', + value: result ?? 'null', + }; + } else if (typeof entrypoint.fn === 'object') { + // Try to run fixture as a react component. This is necessary because not + // all components are functions (some are ForwardRef or Memo objects). + const result = render( + React.createElement(entrypoint.fn as any, entrypoint.params[0]), + ).container.innerHTML; + + return { + kind: 'ok', + value: result ?? 'null', + }; + } else { + const result = render(React.createElement(WrapperTestComponent, entrypoint)) + .container.innerHTML; + + return { + kind: 'ok', + value: result ?? 'null', + }; + } +}; + +export function doEval(source: string): EvaluatorResult { + 'use strict'; + + const originalConsole = globalThis.console; + const logs: Array = []; + const mockedLog = (...args: Array) => { + logs.push( + `${args.map(arg => { + if (arg instanceof Error) { + return arg.toString(); + } else { + return util.inspect(arg); + } + })}`, + ); + }; + + (globalThis.console as any) = { + info: mockedLog, + log: mockedLog, + warn: mockedLog, + error: (...args: Array) => { + if ( + typeof args[0] === 'string' && + args[0].includes('ReactDOMTestUtils.act` is deprecated') + ) { + // remove this once @testing-library/react is upgraded to React 19. + return; + } + + const stack = new Error().stack?.split('\n', 5) ?? []; + for (const stackFrame of stack) { + // React warns on exceptions thrown during render, we avoid printing + // here to reduce noise in test fixture outputs. + if ( + (stackFrame.includes('at logCaughtError') && + stackFrame.includes('react-dom-client.development.js')) || + (stackFrame.includes('at defaultOnRecoverableError') && + stackFrame.includes('react-dom-client.development.js')) + ) { + return; + } + } + mockedLog(...args); + }, + table: mockedLog, + trace: () => {}, + }; + try { + // source needs to be evaluated in the same scope as invoke + const evalResult: any = eval(` + (() => { + // Exports should be overwritten by source + let exports = { + FIXTURE_ENTRYPOINT: { + fn: globalThis.placeholderFn, + params: [], + }, + }; + let reachedInvoke = false; + try { + // run in an iife to avoid naming collisions + (() => {${source}})(); + reachedInvoke = true; + if (exports.FIXTURE_ENTRYPOINT?.fn === globalThis.placeholderFn) { + return { + kind: "exception", + value: "Fixture not implemented", + }; + } + return evaluateFixtureExport(exports); + } catch (e) { + if (!reachedInvoke) { + return { + kind: "UnexpectedError", + value: e.message, + }; + } else { + return { + kind: "exception", + value: e.message, + }; + } + } + })()`); + + const result = { + ...evalResult, + logs, + }; + return result; + } catch (e) { + // syntax errors will cause the eval to throw and bubble up here + return { + kind: 'UnexpectedError', + value: + 'Unexpected error during eval, possible syntax error?\n' + + e.message + + '\n\nsource:\n' + + source, + logs, + }; + } finally { + globalThis.console = originalConsole; + } +} diff --git a/compiler/packages/snap/src/sprout/index.ts b/compiler/packages/snap/src/sprout/index.ts new file mode 100644 index 000000000000..04748bed28f4 --- /dev/null +++ b/compiler/packages/snap/src/sprout/index.ts @@ -0,0 +1,74 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {EvaluatorResult, doEval} from './evaluator'; + +export type SproutResult = + | {kind: 'success'; value: string} + | {kind: 'invalid'; value: string}; + +function stringify(result: EvaluatorResult): string { + return `(kind: ${result.kind}) ${result.value}${ + result.logs.length > 0 ? `\nlogs: [${result.logs.toString()}]` : '' + }`; +} +function makeError(description: string, value: string): SproutResult { + return { + kind: 'invalid', + value: description + '\n' + value, + }; +} +function logsEqual(a: Array, b: Array) { + if (a.length !== b.length) { + return false; + } + return a.every((val, idx) => val === b[idx]); +} +export function runSprout( + originalCode: string, + forgetCode: string, +): SproutResult { + let forgetResult; + try { + (globalThis as any).__SNAP_EVALUATOR_MODE = 'forget'; + forgetResult = doEval(forgetCode); + } catch (e) { + throw e; + } finally { + (globalThis as any).__SNAP_EVALUATOR_MODE = undefined; + } + if (forgetResult.kind === 'UnexpectedError') { + return makeError('Unexpected error in Forget runner', forgetResult.value); + } + if (originalCode.indexOf('@disableNonForgetInSprout') === -1) { + const nonForgetResult = doEval(originalCode); + + if (nonForgetResult.kind === 'UnexpectedError') { + return makeError( + 'Unexpected error in non-forget runner', + nonForgetResult.value, + ); + } else if ( + forgetResult.kind !== nonForgetResult.kind || + forgetResult.value !== nonForgetResult.value || + !logsEqual(forgetResult.logs, nonForgetResult.logs) + ) { + return makeError( + 'Found differences in evaluator results', + `Non-forget (expected): +${stringify(nonForgetResult)} +Forget: +${stringify(forgetResult)} +`, + ); + } + } + return { + kind: 'success', + value: stringify(forgetResult), + }; +} diff --git a/compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts b/compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts new file mode 100644 index 000000000000..229ee45b0da2 --- /dev/null +++ b/compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts @@ -0,0 +1,319 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type { + Effect, + ValueKind, + ValueReason, +} from 'babel-plugin-react-compiler/src'; +import type {TypeConfig} from 'babel-plugin-react-compiler/src/HIR/TypeSchema'; + +export function makeSharedRuntimeTypeProvider({ + EffectEnum, + ValueKindEnum, + ValueReasonEnum, +}: { + EffectEnum: typeof Effect; + ValueKindEnum: typeof ValueKind; + ValueReasonEnum: typeof ValueReason; +}) { + return function sharedRuntimeTypeProvider( + moduleName: string, + ): TypeConfig | null { + if (moduleName === 'shared-runtime') { + return { + kind: 'object', + properties: { + default: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [], + restParam: EffectEnum.Read, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + graphql: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [], + restParam: EffectEnum.Read, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + typedArrayPush: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [EffectEnum.Store, EffectEnum.Capture], + restParam: EffectEnum.Capture, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + typedLog: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [], + restParam: EffectEnum.Read, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + useFreeze: { + kind: 'hook', + returnType: {kind: 'type', name: 'Any'}, + }, + useFragment: { + kind: 'hook', + returnType: {kind: 'type', name: 'MixedReadonly'}, + noAlias: true, + }, + useNoAlias: { + kind: 'hook', + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + noAlias: true, + }, + typedIdentity: { + kind: 'function', + positionalParams: [EffectEnum.Read], + restParam: null, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@value'], + rest: null, + returns: '@return', + temporaries: [], + effects: [{kind: 'Assign', from: '@value', into: '@return'}], + }, + }, + typedAssign: { + kind: 'function', + positionalParams: [EffectEnum.Read], + restParam: null, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@value'], + rest: null, + returns: '@return', + temporaries: [], + effects: [{kind: 'Assign', from: '@value', into: '@return'}], + }, + }, + typedAlias: { + kind: 'function', + positionalParams: [EffectEnum.Read], + restParam: null, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@value'], + rest: null, + returns: '@return', + temporaries: [], + effects: [ + { + kind: 'Create', + into: '@return', + value: ValueKindEnum.Mutable, + reason: ValueReasonEnum.KnownReturnSignature, + }, + {kind: 'Alias', from: '@value', into: '@return'}, + ], + }, + }, + typedCapture: { + kind: 'function', + positionalParams: [EffectEnum.Read], + restParam: null, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Array'}, + returnValueKind: ValueKindEnum.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@value'], + rest: null, + returns: '@return', + temporaries: [], + effects: [ + { + kind: 'Create', + into: '@return', + value: ValueKindEnum.Mutable, + reason: ValueReasonEnum.KnownReturnSignature, + }, + {kind: 'Capture', from: '@value', into: '@return'}, + ], + }, + }, + typedCreateFrom: { + kind: 'function', + positionalParams: [EffectEnum.Read], + restParam: null, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + aliasing: { + receiver: '@receiver', + params: ['@value'], + rest: null, + returns: '@return', + temporaries: [], + effects: [{kind: 'CreateFrom', from: '@value', into: '@return'}], + }, + }, + typedMutate: { + kind: 'function', + positionalParams: [EffectEnum.Read, EffectEnum.Capture], + restParam: null, + calleeEffect: EffectEnum.Store, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + aliasing: { + receiver: '@receiver', + params: ['@object', '@value'], + rest: null, + returns: '@return', + temporaries: [], + effects: [ + { + kind: 'Create', + into: '@return', + value: ValueKindEnum.Primitive, + reason: ValueReasonEnum.KnownReturnSignature, + }, + {kind: 'Mutate', value: '@object'}, + {kind: 'Capture', from: '@value', into: '@object'}, + ], + }, + }, + PanResponder: { + kind: 'object', + properties: { + create: { + kind: 'function', + positionalParams: [EffectEnum.Freeze], + restParam: null, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Frozen, + aliasing: { + receiver: '@receiver', + params: ['@config'], + rest: null, + returns: '@returns', + temporaries: [], + effects: [ + { + kind: 'Freeze', + value: '@config', + reason: ValueReasonEnum.KnownReturnSignature, + }, + { + kind: 'Create', + into: '@returns', + value: ValueKindEnum.Frozen, + reason: ValueReasonEnum.KnownReturnSignature, + }, + { + kind: 'ImmutableCapture', + from: '@config', + into: '@returns', + }, + ], + }, + }, + }, + }, + }, + }; + } else if (moduleName === 'ReactCompilerKnownIncompatibleTest') { + /** + * Fake module used for testing validation of known incompatible + * API validation + */ + return { + kind: 'object', + properties: { + useKnownIncompatible: { + kind: 'hook', + positionalParams: [], + restParam: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + knownIncompatible: `useKnownIncompatible is known to be incompatible`, + }, + useKnownIncompatibleIndirect: { + kind: 'hook', + positionalParams: [], + restParam: EffectEnum.Read, + returnType: { + kind: 'object', + properties: { + incompatible: { + kind: 'function', + positionalParams: [], + restParam: EffectEnum.Read, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + knownIncompatible: `useKnownIncompatibleIndirect returns an incompatible() function that is known incompatible`, + }, + }, + }, + }, + knownIncompatible: { + kind: 'function', + positionalParams: [], + restParam: EffectEnum.Read, + calleeEffect: EffectEnum.Read, + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + knownIncompatible: `useKnownIncompatible is known to be incompatible`, + }, + }, + }; + } else if (moduleName === 'ReactCompilerTest') { + /** + * Fake module used for testing validation that type providers return hook + * types for hook names and non-hook types for non-hook names + */ + return { + kind: 'object', + properties: { + useHookNotTypedAsHook: { + kind: 'type', + name: 'Any', + }, + notAhookTypedAsHook: { + kind: 'hook', + returnType: {kind: 'type', name: 'Any'}, + }, + }, + }; + } else if (moduleName === 'useDefaultExportNotTypedAsHook') { + /** + * Fake module used for testing validation that type providers return hook + * types for hook names and non-hook types for non-hook names + */ + return { + kind: 'object', + properties: { + default: { + kind: 'type', + name: 'Any', + }, + }, + }; + } + return null; + }; +} diff --git a/compiler/packages/snap/src/sprout/shared-runtime.ts b/compiler/packages/snap/src/sprout/shared-runtime.ts new file mode 100644 index 000000000000..2a2265d70988 --- /dev/null +++ b/compiler/packages/snap/src/sprout/shared-runtime.ts @@ -0,0 +1,430 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {IntlVariations, IntlViewerContext, init} from 'fbt'; +import React, {FunctionComponent} from 'react'; + +/** + * This file is meant for use by `runner-evaluator` and fixture tests. + * + * Any fixture test can import constants or functions exported here. + * However, the import path must be the relative path from `runner-evaluator` + * (which calls `eval` on each fixture) to this file. + * + * ```js + * // test.js + * import {CONST_STRING0} from './shared-runtime'; + * + * // ... + * ``` + */ + +export type StringKeyedObject = {[key: string]: unknown}; + +export const CONST_STRING0 = 'global string 0'; +export const CONST_STRING1 = 'global string 1'; +export const CONST_STRING2 = 'global string 2'; + +export const CONST_NUMBER0 = 0; +export const CONST_NUMBER1 = 1; +export const CONST_NUMBER2 = 2; + +export const CONST_TRUE = true; +export const CONST_FALSE = false; + +export function initFbt(): void { + const viewerContext: IntlViewerContext = { + GENDER: IntlVariations.GENDER_UNKNOWN, + locale: 'en_US', + }; + + init({ + translations: {}, + hooks: { + getViewerContext: () => viewerContext, + }, + }); +} + +export function mutate(arg: any): void { + // don't mutate primitive + if (arg == null || typeof arg !== 'object') { + return; + } else if (Array.isArray(arg)) { + arg.push('joe'); + } + + let count: number = 0; + let key; + while (true) { + key = 'wat' + count; + if (!Object.hasOwn(arg, key)) { + arg[key] = 'joe'; + return; + } + count++; + } +} + +export function mutateAndReturn(arg: T): T { + mutate(arg); + return arg; +} + +export function mutateAndReturnNewValue(arg: T): string { + mutate(arg); + return 'hello!'; +} + +export function setProperty(arg: any, property: any): void { + // don't mutate primitive + if (arg == null || typeof arg !== 'object') { + return arg; + } + + let count: number = 0; + let key; + while (true) { + key = 'wat' + count; + if (!Object.hasOwn(arg, key)) { + arg[key] = property; + return arg; + } + count++; + } +} + +export function setPropertyByKey< + T, + TKey extends keyof T, + TProperty extends T[TKey], +>(arg: T, key: TKey, property: TProperty): T { + arg[key] = property; + return arg; +} + +export function arrayPush(arr: Array, ...values: Array): Array { + arr.push(...values); + return arr; +} + +export function graphql(value: string): string { + return value; +} + +export function identity(x: T): T { + return x; +} + +export function getNumber(): number { + return 4; +} + +export function getNull(): null { + return null; +} + +export function getTrue(): true { + return true; +} + +export function getFalse(): false { + return false; +} + +export function calculateExpensiveNumber(x: number): number { + return x; +} + +/** + * Functions that do not mutate their parameters + */ +export function shallowCopy(obj: T): T { + return Object.assign({}, obj); +} + +export function makeObject_Primitives(): StringKeyedObject { + return {a: 0, b: 'value1', c: true}; +} + +export function makeArray(...values: Array): Array { + return [...values]; +} + +export function addOne(value: number): number { + return value + 1; +} + +/* + * Alias console.log, as it is defined as a global and may have + * different compiler handling than unknown functions + */ +export function print(...args: Array): void { + console.log(...args); +} + +export function sum(...args: Array): number { + return args.reduce((result, arg) => result + arg, 0); +} + +export function throwErrorWithMessage(message: string): never { + throw new Error(message); +} + +export function throwInput(x: object): never { + throw x; +} + +export function throwErrorWithMessageIf(cond: boolean, message: string): void { + if (cond) { + throw new Error(message); + } +} + +export function logValue(value: T): void { + console.log(value); +} + +export function useHook(): object { + return makeObject_Primitives(); +} + +const noAliasObject = Object.freeze({}); +export function useNoAlias(..._args: Array): object { + return noAliasObject; +} + +export function useIdentity(arg: T): T { + return arg; +} + +export function invoke, ReturnType>( + fn: (...input: T) => ReturnType, + ...params: T +): ReturnType { + return fn(...params); +} + +export function conditionalInvoke, ReturnType>( + shouldInvoke: boolean, + fn: (...input: T) => ReturnType, + ...params: T +): ReturnType | null { + if (shouldInvoke) { + return fn(...params); + } else { + return null; + } +} + +/** + * React Components + */ +export function Text(props: { + value: string; + children?: Array; +}): React.ReactElement { + return React.createElement('div', null, props.value, props.children); +} + +export function StaticText1(props: { + children?: Array; +}): React.ReactElement { + return React.createElement('div', null, 'StaticText1', props.children); +} + +export function StaticText2(props: { + children?: Array; +}): React.ReactElement { + return React.createElement('div', null, 'StaticText2', props.children); +} + +export function RenderPropAsChild(props: { + items: Array<() => React.ReactNode>; +}): React.ReactElement { + return React.createElement( + 'div', + null, + 'HigherOrderComponent', + props.items.map(item => item()), + ); +} + +export function Stringify(props: any): React.ReactElement { + return React.createElement( + 'div', + null, + toJSON(props, props?.shouldInvokeFns), + ); +} +export function Throw() { + throw new Error(); +} + +export function ValidateMemoization({ + inputs, + output: rawOutput, + onlyCheckCompiled = false, +}: { + inputs: Array; + output: any; + onlyCheckCompiled?: boolean; +}): React.ReactElement { + 'use no forget'; + // Wrap rawOutput as it might be a function, which useState would invoke. + const output = {value: rawOutput}; + const [previousInputs, setPreviousInputs] = React.useState(inputs); + const [previousOutput, setPreviousOutput] = React.useState(output); + if ( + !onlyCheckCompiled || + (onlyCheckCompiled && + (globalThis as any).__SNAP_EVALUATOR_MODE === 'forget') + ) { + if ( + inputs.length !== previousInputs.length || + inputs.some((item, i) => item !== previousInputs[i]) + ) { + // Some input changed, we expect the output to change + setPreviousInputs(inputs); + setPreviousOutput(output); + } else if (output.value !== previousOutput.value) { + // Else output should be stable + throw new Error('Output identity changed but inputs did not'); + } + } + return React.createElement(Stringify, {inputs, output: rawOutput}); +} + +export function createHookWrapper( + useMaybeHook: (props: TProps) => TRet, +): FunctionComponent { + return function Component(props: TProps): React.ReactElement { + const result = useMaybeHook(props); + return Stringify({ + result: result, + shouldInvokeFns: true, + }); + }; +} + +// helper functions +export function toJSON(value: any, invokeFns: boolean = false): string { + const seen = new Map(); + + return JSON.stringify(value, (_key: string, val: any) => { + if (typeof val === 'function') { + if (val.length === 0 && invokeFns) { + return { + kind: 'Function', + result: val(), + }; + } else { + return `[[ function params=${val.length} ]]`; + } + } else if (typeof val === 'object') { + let id = seen.get(val); + if (id != null) { + return `[[ cyclic ref *${id} ]]`; + } else if (val instanceof Map) { + return { + kind: 'Map', + value: Array.from(val.entries()), + }; + } else if (val instanceof Set) { + return { + kind: 'Set', + value: Array.from(val.values()), + }; + } + seen.set(val, seen.size); + } + return val; + }); +} +export class Builder { + vals: Array = []; + static makeBuilder(isNull: boolean, ...args: Array): Builder | null { + if (isNull) { + return null; + } else { + const builder = new Builder(); + builder.push(...args); + return builder; + } + } + push(...args: Array): Builder { + this.vals.push(...args); + return this; + } +} + +export const ObjectWithHooks = { + useFoo(): number { + return 0; + }, + useMakeArray(): Array { + return [1, 2, 3]; + }, + useIdentity(arg: T): T { + return arg; + }, +}; + +export function useFragment(..._args: Array): object { + return { + a: [1, 2, 3], + b: {c: {d: 4}}, + }; +} + +export function useSpecialEffect( + fn: () => any, + _secondArg: any, + deps: Array, +) { + React.useEffect(fn, deps); +} + +export function typedArrayPush(array: Array, item: T): void { + array.push(item); +} + +export function typedLog(...values: Array): void { + console.log(...values); +} + +export function typedIdentity(value: T): T { + return value; +} + +export function typedAssign(x: T): T { + return x; +} + +export function typedAlias(x: T): T { + return x; +} + +export function typedCapture(x: T): Array { + return [x]; +} + +export function typedCreateFrom(array: Array): T { + return array[0]; +} + +export function typedMutate(x: any, v: any = null): void { + x.property = v; +} + +export const PanResponder = { + create(obj: any): any { + return obj; + }, +}; + +export default typedLog; diff --git a/compiler/packages/snap/src/sprout/useEffectWrapper.ts b/compiler/packages/snap/src/sprout/useEffectWrapper.ts new file mode 100644 index 000000000000..b1589dac4072 --- /dev/null +++ b/compiler/packages/snap/src/sprout/useEffectWrapper.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* This file is used to test the effect auto-deps configuration, which + * allows you to specify functions that should have dependencies added to + * callsites. + */ +import {useEffect} from 'react'; + +export default function useEffectWrapper(f: () => void | (() => void)): void { + useEffect(() => { + f(); + }, [f]); +} diff --git a/compiler/packages/snap/src/types.d.ts b/compiler/packages/snap/src/types.d.ts new file mode 100644 index 000000000000..103ed5c93a0e --- /dev/null +++ b/compiler/packages/snap/src/types.d.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// v0.17.1 +declare module 'hermes-parser' { + type HermesParserOptions = { + allowReturnOutsideFunction?: boolean; + babel?: boolean; + flow?: 'all' | 'detect'; + enableExperimentalComponentSyntax?: boolean; + enableExperimentalFlowMatchSyntax?: boolean; + sourceFilename?: string; + sourceType?: 'module' | 'script' | 'unambiguous'; + tokens?: boolean; + }; + export function parse(code: string, options: Partial); +} diff --git a/compiler/packages/snap/tsconfig.json b/compiler/packages/snap/tsconfig.json new file mode 100644 index 000000000000..668e8145646d --- /dev/null +++ b/compiler/packages/snap/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "@tsconfig/strictest/tsconfig.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "declaration": true, + "outDir": "dist", + "jsx": "react-jsxdev", + "lib": ["ES2022"], + + // weaken strictness from preset + "importsNotUsedAsValues": "remove", + "noUncheckedIndexedAccess": false, + "noUnusedParameters": false, + "useUnknownInCatchVariables": false, + "target": "ES2015", + // ideally turn off only during dev, or on a per-file basis + "noUnusedLocals": false, + "sourceMap": true + }, + "exclude": ["node_modules"], + "include": ["src/**/*.ts"], +} diff --git a/compiler/scripts/anonymize.js b/compiler/scripts/anonymize.js new file mode 100644 index 000000000000..278e582c101d --- /dev/null +++ b/compiler/scripts/anonymize.js @@ -0,0 +1,250 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const fs = require('fs'); +const HermesParser = require('hermes-parser'); +const BabelParser = require('@babel/parser'); +const BabelCore = require('@babel/core'); +const invariant = require('invariant'); +const {argv, stdin} = require('process'); +const prettier = require('prettier'); +const {JSXText} = require('hermes-parser/dist/generated/ESTreeVisitorKeys'); + +function runPlugin(text, file, language) { + let ast; + if (language === 'flow') { + ast = HermesParser.parse(text, { + babel: true, + flow: 'all', + sourceFilename: file, + sourceType: 'module', + enableExperimentalComponentSyntax: true, + }); + } else { + ast = BabelParser.parse(text, { + sourceFilename: file, + plugins: ['typescript', 'jsx'], + sourceType: 'module', + }); + } + const result = BabelCore.transformFromAstSync(ast, text, { + ast: false, + filename: file, + highlightCode: false, + retainLines: true, + plugins: [[AnonymizePlugin]], + sourceType: 'module', + configFile: false, + babelrc: false, + }); + invariant( + result?.code != null, + `Expected BabelPluginReactForget to codegen successfully, got: ${result}` + ); + return result.code; +} + +async function format(code, language) { + return await prettier.format(code, { + semi: true, + parser: language === 'typescript' ? 'babel-ts' : 'flow', + }); +} + +const TAG_NAMES = new Set([ + 'a', + 'body', + 'button', + 'div', + 'form', + 'head', + 'html', + 'input', + 'label', + 'select', + 'span', + 'textarea', + + // property/attribute names + 'value', + 'checked', + 'onClick', + 'onSubmit', + 'name', +]); + +const BUILTIN_HOOKS = new Set([ + 'useContext', + 'useEffect', + 'useInsertionEffect', + 'useLayoutEffect', + 'useReducer', + 'useState', +]); + +const GLOBALS = new Set([ + 'String', + 'Object', + 'Function', + 'Number', + 'RegExp', + 'Date', + 'Error', + 'Function', + 'TypeError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'URIError', + 'EvalError', + 'Boolean', + 'DataView', + 'Float32Array', + 'Float64Array', + 'Int8Array', + 'Int16Array', + 'Int32Array', + 'Map', + 'Set', + 'WeakMap', + 'Uint8Array', + 'Uint8ClampedArray', + 'Uint16Array', + 'Uint32Array', + 'ArrayBuffer', + 'JSON', + 'parseFloat', + 'parseInt', + 'console', + 'isNaN', + 'eval', + 'isFinite', + 'encodeURI', + 'decodeURI', + 'encodeURIComponent', + 'decodeURIComponent', + + // common method/property names of globals + 'map', + 'push', + 'at', + 'filter', + 'slice', + 'splice', + 'add', + 'get', + 'set', + 'has', + 'size', + 'length', + 'toString', +]); + +function AnonymizePlugin(_babel) { + let index = 0; + const identifiers = new Map(); + const literals = new Map(); + return { + name: 'anonymize', + visitor: { + JSXNamespacedName(path) { + throw error('TODO: handle JSXNamedspacedName'); + }, + JSXIdentifier(path) { + const name = path.node.name; + if (TAG_NAMES.has(name)) { + return; + } + let nextName = identifiers.get(name); + if (nextName == null) { + const isCapitalized = + name.slice(0, 1).toUpperCase() === name.slice(0, 1); + nextName = isCapitalized + ? `Component${(index++).toString(16).toUpperCase()}` + : `c${(index++).toString(16)}`; + identifiers.set(name, nextName); + } + path.node.name = nextName; + }, + Identifier(path) { + const name = path.node.name; + if (BUILTIN_HOOKS.has(name) || GLOBALS.has(name)) { + return; + } + let nextName = identifiers.get(name); + if (nextName == null) { + const isCapitalized = + name.slice(0, 1).toUpperCase() === name.slice(0, 1); + const prefix = isCapitalized ? 'V' : 'v'; + nextName = `${prefix}${(index++).toString(16)}`; + if (name.startsWith('use')) { + nextName = + 'use' + nextName.slice(0, 1).toUpperCase() + nextName.slice(1); + } + identifiers.set(name, nextName); + } + path.node.name = nextName; + }, + JSXText(path) { + const value = path.node.value; + let nextValue = literals.get(value); + if (nextValue == null) { + let string = ''; + while (string.length < value.length) { + string += String.fromCharCode(Math.round(Math.random() * 25) + 97); + } + nextValue = string; + literals.set(value, nextValue); + } + path.node.value = nextValue; + }, + StringLiteral(path) { + const value = path.node.value; + let nextValue = literals.get(value); + if (nextValue == null) { + let string = ''; + while (string.length < value.length) { + string += String.fromCharCode(Math.round(Math.random() * 58) + 65); + } + nextValue = string; + literals.set(value, nextValue); + } + path.node.value = nextValue; + }, + NumericLiteral(path) { + const value = path.node.value; + let nextValue = literals.get(value); + if (nextValue == null) { + nextValue = Number.isInteger(value) + ? Math.round(Math.random() * Number.MAX_SAFE_INTEGER) + : Math.random() * Number.MAX_VALUE; + literals.set(value, nextValue); + } + path.node.value = nextValue; + }, + }, + }; +} + +let file; +let text; +if (argv.length >= 3) { + file = argv[2]; + text = fs.readFileSync(file, 'utf8'); +} else { + // read from stdin + file = 'stdin.js'; + text = fs.readFileSync(stdin.fd, 'utf8'); +} +const language = + file.endsWith('.ts') || file.endsWith('.tsx') ? 'typescript' : 'flow'; +const result = runPlugin(text, file, language); +format(result, language).then(formatted => { + console.log(formatted); +}); diff --git a/compiler/scripts/babel-ast-to-json.mjs b/compiler/scripts/babel-ast-to-json.mjs new file mode 100644 index 000000000000..6112c90907b0 --- /dev/null +++ b/compiler/scripts/babel-ast-to-json.mjs @@ -0,0 +1,343 @@ +import { parse } from "@babel/parser"; +import _traverse from "@babel/traverse"; +const traverse = _traverse.default || _traverse; +import fs from "fs"; +import path from "path"; +import fg from "fast-glob"; +const { globSync } = fg; + +const FIXTURE_DIR = process.argv[2]; // source dir with JS/TS files +const OUTPUT_DIR = process.argv[3]; // output dir for JSON files + +if (!FIXTURE_DIR || !OUTPUT_DIR) { + console.error( + "Usage: node babel-ast-to-json.mjs " + ); + process.exit(1); +} + +// Find all fixture source files +const fixtures = globSync("**/*.{js,ts,tsx,jsx}", { cwd: FIXTURE_DIR }); + +function getScopeKind(babelScope) { + const blockType = babelScope.block.type; + switch (blockType) { + case "Program": + return "program"; + case "FunctionDeclaration": + case "FunctionExpression": + case "ArrowFunctionExpression": + case "ObjectMethod": + case "ClassMethod": + case "ClassPrivateMethod": + return "function"; + case "BlockStatement": + return "block"; + case "ForStatement": + case "ForInStatement": + case "ForOfStatement": + return "for"; + case "ClassDeclaration": + case "ClassExpression": + return "class"; + case "SwitchStatement": + return "switch"; + case "CatchClause": + return "catch"; + default: + return "block"; + } +} + +function getBindingKind(babelKind) { + switch (babelKind) { + case "var": + return "var"; + case "let": + return "let"; + case "const": + return "const"; + case "param": + return "param"; + case "module": + return "module"; + case "hoisted": + return "hoisted"; + case "local": + return "local"; + default: + return "unknown"; + } +} + +function getImportData(binding) { + if (binding.path.isImportSpecifier()) { + const imported = binding.path.node.imported; + return { + source: binding.path.parent.source.value, + kind: "named", + imported: imported.type === "StringLiteral" ? imported.value : imported.name, + }; + } else if (binding.path.isImportDefaultSpecifier()) { + return { + source: binding.path.parent.source.value, + kind: "default", + }; + } else if (binding.path.isImportNamespaceSpecifier()) { + return { + source: binding.path.parent.source.value, + kind: "namespace", + }; + } + return null; +} + +function collectScopeInfo(ast) { + const scopeMap = new Map(); // Babel scope -> ScopeId + const bindingMap = new Map(); // Babel binding -> BindingId + const scopes = []; + const bindings = []; + const nodeToScope = {}; + const nodeToScopeEnd = {}; + const referenceToBinding = {}; + const refNodeIdToBinding = {}; + const nodeIdToScope = {}; + let nextScopeId = 0; + let nextBindingId = 0; + let nextNodeId = 1; + + function getOrAssignNodeId(node) { + if (node._nodeId == null) { + node._nodeId = nextNodeId++; + } + return node._nodeId; + } + + function mapRef(start, bindingId, node) { + referenceToBinding[String(start)] = bindingId; + const nodeId = getOrAssignNodeId(node); + refNodeIdToBinding[String(nodeId)] = bindingId; + } + + function ensureScope(babelScope) { + if (scopeMap.has(babelScope)) return scopeMap.get(babelScope); + + // Ensure parent is registered first (preorder: parent gets lower ID) + if (babelScope.parent) { + ensureScope(babelScope.parent); + } + + const id = nextScopeId++; + scopeMap.set(babelScope, id); + + const parentId = babelScope.parent ? scopeMap.get(babelScope.parent) : null; + const kind = getScopeKind(babelScope); + const bindingsMap = {}; + + // Register all bindings in this scope + for (const [name, binding] of Object.entries(babelScope.bindings)) { + if (!bindingMap.has(binding)) { + const bid = nextBindingId++; + bindingMap.set(binding, bid); + const declarationNodeId = getOrAssignNodeId(binding.identifier); + const bindingData = { + id: bid, + name, + kind: getBindingKind(binding.kind), + scope: id, + declarationType: binding.path.node.type, + declarationStart: binding.identifier.start, + declarationNodeId, + }; + + // Import bindings + if (binding.kind === "module") { + bindingData.import = getImportData(binding); + } + + bindings.push(bindingData); + } + bindingsMap[name] = bindingMap.get(binding); + } + + scopes.push({ + id, + parent: parentId, + kind, + bindings: bindingsMap, + }); + + // Record node_to_scope and node_to_scope_end + const blockNode = babelScope.block; + if (blockNode.start != null) { + nodeToScope[String(blockNode.start)] = id; + if (blockNode.end != null) { + nodeToScopeEnd[String(blockNode.start)] = blockNode.end; + } + const scopeNodeId = getOrAssignNodeId(blockNode); + nodeIdToScope[String(scopeNodeId)] = id; + } + + return id; + } + + traverse(ast, { + enter(path) { + ensureScope(path.scope); + }, + Identifier(path) { + getOrAssignNodeId(path.node); + if (!path.isReferencedIdentifier()) return; + const binding = path.scope.getBinding(path.node.name); + if (binding && bindingMap.has(binding) && path.node.start != null) { + mapRef(path.node.start, bindingMap.get(binding), path.node); + } + }, + JSXIdentifier(path) { + getOrAssignNodeId(path.node); + }, + AssignmentExpression(path) { + const left = path.get("left"); + if (left.isLVal()) { + mapLValToBindings(left, bindingMap); + } + }, + UpdateExpression(path) { + const argument = path.get("argument"); + if (argument.isLVal()) { + mapLValToBindings(argument, bindingMap); + } + }, + }); + + // Map identifiers in assignment targets (LVal positions) to their bindings. + function mapLValToBindings(lvalPath, bindingMap) { + const node = lvalPath.node; + if (!node) return; + switch (node.type) { + case "Identifier": { + const binding = lvalPath.scope.getBinding(node.name); + if (binding && bindingMap.has(binding) && node.start != null) { + mapRef(node.start, bindingMap.get(binding), node); + } + break; + } + case "ArrayPattern": { + for (const element of lvalPath.get("elements")) { + if (element.node) mapLValToBindings(element, bindingMap); + } + break; + } + case "ObjectPattern": { + for (const property of lvalPath.get("properties")) { + if (property.isObjectProperty()) { + mapLValToBindings(property.get("value"), bindingMap); + } else if (property.isRestElement()) { + mapLValToBindings(property, bindingMap); + } + } + break; + } + case "AssignmentPattern": { + mapLValToBindings(lvalPath.get("left"), bindingMap); + break; + } + case "RestElement": { + mapLValToBindings(lvalPath.get("argument"), bindingMap); + break; + } + default: + break; + } + } + + // Record declaration identifiers in reference_to_binding and refNodeIdToBinding + for (const [binding, bid] of bindingMap) { + if (binding.identifier && binding.identifier.start != null) { + mapRef(binding.identifier.start, bid, binding.identifier); + } + } + + const result = { + scopes, + bindings, + nodeToScope, + referenceToBinding, + programScope: 0, + }; + // Only include new fields when non-empty, matching Rust skip_serializing_if + if (Object.keys(nodeToScopeEnd).length > 0) { + result.nodeToScopeEnd = nodeToScopeEnd; + } + if (Object.keys(refNodeIdToBinding).length > 0) { + result.refNodeIdToBinding = refNodeIdToBinding; + } + if (Object.keys(nodeIdToScope).length > 0) { + result.nodeIdToScope = nodeIdToScope; + } + return result; +} + +function renameIdentifiers(ast, scopeInfo) { + traverse(ast, { + Identifier(path) { + const nodeId = path.node._nodeId; + if (nodeId != null && String(nodeId) in scopeInfo.refNodeIdToBinding) { + const bindingId = scopeInfo.refNodeIdToBinding[String(nodeId)]; + const binding = scopeInfo.bindings[bindingId]; + path.node.name = `${path.node.name}_${binding.scope}_${bindingId}`; + } + }, + }); +} + +let parsed = 0; +let errors = 0; + +for (const fixture of fixtures) { + const input = fs.readFileSync(path.join(FIXTURE_DIR, fixture), "utf8"); + const isFlow = input.includes("@flow"); + + const plugins = isFlow ? ["flow", "jsx"] : ["typescript", "jsx"]; + // Default to module unless there's an indicator it should be script + const sourceType = "module"; + + try { + const ast = parse(input, { + sourceFilename: fixture, + plugins, + sourceType, + allowReturnOutsideFunction: true, + errorRecovery: true, + }); + + // Collect scope info first โ€” this assigns _nodeId to Identifier nodes + const scopeInfo = collectScopeInfo(ast); + + // Serialize AST after scope collection so _nodeId fields are included + const outPath = path.join(OUTPUT_DIR, fixture + ".json"); + fs.mkdirSync(path.dirname(outPath), { recursive: true }); + fs.writeFileSync(outPath, JSON.stringify(ast, null, 2)); + + // Write scope info + const scopeOutPath = path.join(OUTPUT_DIR, fixture + ".scope.json"); + fs.writeFileSync(scopeOutPath, JSON.stringify(scopeInfo, null, 2)); + + // Create renamed AST for scope resolution verification + renameIdentifiers(ast, scopeInfo); + const renamedOutPath = path.join(OUTPUT_DIR, fixture + ".renamed.json"); + fs.writeFileSync(renamedOutPath, JSON.stringify(ast, null, 2)); + + parsed++; + } catch (e) { + // Parse errors are expected for some fixtures + const outPath = path.join(OUTPUT_DIR, fixture + ".parse-error"); + fs.mkdirSync(path.dirname(outPath), { recursive: true }); + fs.writeFileSync(outPath, e.message); + errors++; + } +} + +console.log( + `Parsed ${parsed} fixtures, ${errors} parse errors, ${fixtures.length} total` +); diff --git a/compiler/scripts/build-eslint-docs.js b/compiler/scripts/build-eslint-docs.js new file mode 100644 index 000000000000..f4e411590e84 --- /dev/null +++ b/compiler/scripts/build-eslint-docs.js @@ -0,0 +1,34 @@ +const ReactCompiler = require('../packages/babel-plugin-react-compiler/dist'); + +const combinedRules = [ + { + name: 'rules-of-hooks', + recommended: true, + description: + 'Validates that components and hooks follow the [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks)', + }, + { + name: 'exhaustive-deps', + recommended: true, + description: + 'Validates that hooks which accept dependency arrays (`useMemo()`, `useCallback()`, `useEffect()`, etc) ' + + 'list all referenced variables in their dependency array. Referencing a value without including it in the ' + + 'dependency array can lead to stale UI or callbacks.', + }, + ...ReactCompiler.LintRules, +]; + +const printed = combinedRules + .filter( + ruleConfig => ruleConfig.rule.recommended && ruleConfig.severity !== 'Off' + ) + .map(ruleConfig => { + return ` +## \`react-hooks/${ruleConfig.rule.name}\` + +${ruleConfig.rule.description} + `.trim(); + }) + .join('\n\n'); + +console.log(printed); diff --git a/compiler/scripts/copyright.js b/compiler/scripts/copyright.js new file mode 100644 index 000000000000..0a5ef2e29ae3 --- /dev/null +++ b/compiler/scripts/copyright.js @@ -0,0 +1,68 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const fs = require('fs'); +const glob = require('glob'); + +const META_COPYRIGHT_COMMENT_BLOCK = + `/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */`.trim() + '\n\n'; + +const files = glob.sync('**/*.{js,ts,tsx,jsx,rs}', { + ignore: [ + '**/dist/**', + '**/node_modules/**', + '**/tests/fixtures/**', + '**/__tests__/fixtures/**', + ], +}); + +const updatedFiles = new Map(); +let hasErrors = false; +files.forEach(file => { + try { + const result = processFile(file); + if (result != null) { + updatedFiles.set(file, result); + } + } catch (e) { + console.error(e); + hasErrors = true; + } +}); +if (hasErrors) { + console.error('Update failed'); + process.exit(1); +} else { + for (const [file, source] of updatedFiles) { + fs.writeFileSync(file, source, 'utf8'); + } + console.log('Update complete'); +} + +function processFile(file) { + if (fs.lstatSync(file).isDirectory()) { + return; + } + let source = fs.readFileSync(file, 'utf8'); + + if (source.indexOf(META_COPYRIGHT_COMMENT_BLOCK) === 0) { + return null; + } + if (/^\/\*\*/.test(source)) { + source = source.replace(/\/\*\*[^\/]+\/\s+/, META_COPYRIGHT_COMMENT_BLOCK); + } else { + source = `${META_COPYRIGHT_COMMENT_BLOCK}${source}`; + } + return source; +} diff --git a/compiler/scripts/debug-print-error.mjs b/compiler/scripts/debug-print-error.mjs new file mode 100644 index 000000000000..48a9389ef9bb --- /dev/null +++ b/compiler/scripts/debug-print-error.mjs @@ -0,0 +1,110 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Debug error printer for the Rust port testing infrastructure. + * + * Prints a detailed representation of CompilerError/CompilerDiagnostic objects, + * including all fields: category, severity, reason, description, loc, + * suggestions, and nested details. + * + * Format matches the testing infrastructure plan: + * + * Error: + * category: InvalidReact + * severity: InvalidReact + * reason: "Hooks must be called unconditionally" + * description: "Cannot call a hook (useState) conditionally" + * loc: 3:4-3:20 + * suggestions: [] + * details: + * - kind: error + * loc: 2:2-5:3 + * message: "This is a conditional" + */ + +/** + * Format a source location for debug output. + * @param {object|symbol|null} loc + * @returns {string} + */ +export function formatSourceLocation(loc) { + if (loc == null || typeof loc === "symbol") { + return "generated"; + } + return `${loc.start.line}:${loc.start.column}-${loc.end.line}:${loc.end.column}`; +} + +/** + * Format a CompilerError (with details array) into a debug string. + * @param {object} error - A CompilerError instance + * @returns {string} + */ +export function debugPrintError(error) { + const lines = []; + + if (error.details && error.details.length > 0) { + for (const detail of error.details) { + lines.push("Error:"); + lines.push(` category: ${detail.category ?? "unknown"}`); + lines.push(` severity: ${detail.severity ?? "unknown"}`); + lines.push(` reason: ${JSON.stringify(detail.reason ?? "")}`); + + if (detail.description != null) { + lines.push(` description: ${JSON.stringify(detail.description)}`); + } else { + lines.push(` description: null`); + } + + // Handle loc: CompilerDiagnostic uses primaryLocation(), CompilerErrorDetail uses .loc + const loc = + typeof detail.primaryLocation === "function" + ? detail.primaryLocation() + : detail.loc; + lines.push(` loc: ${formatSourceLocation(loc)}`); + + const suggestions = detail.suggestions ?? []; + if (suggestions.length === 0) { + lines.push(` suggestions: []`); + } else { + lines.push(` suggestions:`); + for (const s of suggestions) { + lines.push(` - op: ${s.op}`); + lines.push(` range: [${s.range[0]}, ${s.range[1]}]`); + lines.push(` description: ${JSON.stringify(s.description)}`); + if (s.text != null) { + lines.push(` text: ${JSON.stringify(s.text)}`); + } + } + } + + // Handle details array for CompilerDiagnostic (new-style errors) + if ( + detail.options && + detail.options.details && + detail.options.details.length > 0 + ) { + lines.push(` details:`); + for (const d of detail.options.details) { + if (d.kind === "error") { + lines.push(` - kind: error`); + lines.push(` loc: ${formatSourceLocation(d.loc)}`); + lines.push(` message: ${JSON.stringify(d.message)}`); + } else if (d.kind === "hint") { + lines.push(` - kind: hint`); + lines.push(` message: ${JSON.stringify(d.message)}`); + } + } + } + } + } else { + lines.push("Error:"); + lines.push(` message: ${JSON.stringify(error.message)}`); + } + + return lines.join("\n") + "\n"; +} diff --git a/compiler/scripts/debug-print-hir.mjs b/compiler/scripts/debug-print-hir.mjs new file mode 100644 index 000000000000..846e0bcba736 --- /dev/null +++ b/compiler/scripts/debug-print-hir.mjs @@ -0,0 +1,1193 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Debug HIR printer for the Rust port testing infrastructure. + * + * Custom printer that walks the HIRFunction structure and prints every field + * of every identifier, instruction, terminal, and block. Also includes + * outlined functions (from FunctionExpression instruction values). + * + * This does NOT delegate to printFunctionWithOutlined() โ€” it is a standalone + * walker that produces a detailed, deterministic representation suitable for + * cross-compiler comparison between the TS and Rust implementations. + * + * @param {Function} _printFunctionWithOutlined - Unused (kept for API compat) + * @param {object} hirFunction - The HIRFunction to print + * @returns {string} The debug representation + */ +export function debugPrintHIR(_printFunctionWithOutlined, hirFunction) { + const outlined = []; + const result = printHIRFunction(hirFunction, 0, outlined); + const parts = [result]; + for (let i = 0; i < outlined.length; i++) { + parts.push(printHIRFunction(outlined[i], i + 1, outlined)); + } + return parts.join("\n\n"); +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function indent(depth) { + return " ".repeat(depth); +} + +function formatLoc(loc) { + if (loc == null || typeof loc === "symbol") { + return "generated"; + } + return `${loc.start.line}:${loc.start.column}-${loc.end.line}:${loc.end.column}`; +} + +function formatEffect(effect) { + // Effect enum values in the TS compiler are lowercase strings like + // "read", "mutate", "", etc. + return String(effect); +} + +function formatType(type) { + if (type == null) return "Type"; + switch (type.kind) { + case "Type": + return "Type"; + case "Primitive": + return "Primitive"; + case "Object": + return type.shapeId != null ? `Object<${type.shapeId}>` : "Object"; + case "Function": { + const ret = formatType(type.return); + const base = + type.shapeId != null ? `Function<${type.shapeId}>` : "Function"; + return ret !== "Type" ? `${base}():${ret}` : base; + } + case "Poly": + return "Poly"; + case "Phi": { + const ops = type.operands.map(formatType).join(", "); + return `Phi(${ops})`; + } + case "Property": { + const objType = formatType(type.objectType); + return `Property(${objType}.${type.objectName})`; + } + case "ObjectMethod": + return "ObjectMethod"; + default: + return "Type"; + } +} + +function formatIdentifierName(name) { + if (name == null) return "null"; + if (typeof name === "object" && name.value != null) { + return JSON.stringify(name.value); + } + return JSON.stringify(String(name)); +} + +function formatMutableRange(range) { + if (range == null) return "[0:0]"; + return `[${range.start}:${range.end}]`; +} + +function formatScopeId(scope) { + if (scope == null) return "null"; + return `@${scope.id}`; +} + +function formatDeclarationId(id) { + if (id == null) return "null"; + return String(id); +} + +// --------------------------------------------------------------------------- +// Place printing +// --------------------------------------------------------------------------- + +function printPlaceInline(place, depth) { + const id = place.identifier; + return [ + `${indent(depth)}Place {`, + `${indent(depth + 1)}identifier: $${id.id}`, + `${indent(depth + 1)}effect: ${formatEffect(place.effect)}`, + `${indent(depth + 1)}reactive: ${place.reactive}`, + `${indent(depth + 1)}loc: ${formatLoc(place.loc)}`, + `${indent(depth)}}`, + ].join("\n"); +} + +// --------------------------------------------------------------------------- +// Identifier printing +// --------------------------------------------------------------------------- + +function printIdentifierEntry(identifier, depth) { + return [ + `${indent(depth)}$${identifier.id}: Identifier {`, + `${indent(depth + 1)}id: ${identifier.id}`, + `${indent(depth + 1)}declarationId: ${formatDeclarationId(identifier.declarationId)}`, + `${indent(depth + 1)}name: ${formatIdentifierName(identifier.name)}`, + `${indent(depth + 1)}mutableRange: ${formatMutableRange(identifier.mutableRange)}`, + `${indent(depth + 1)}scope: ${formatScopeId(identifier.scope)}`, + `${indent(depth + 1)}type: ${formatType(identifier.type)}`, + `${indent(depth + 1)}loc: ${formatLoc(identifier.loc)}`, + `${indent(depth)}}`, + ].join("\n"); +} + +// --------------------------------------------------------------------------- +// InstructionValue printing +// --------------------------------------------------------------------------- + +function printObjectPropertyKey(key) { + switch (key.kind) { + case "identifier": + return key.name; + case "string": + return `"${key.name}"`; + case "computed": + return `[$${key.name.identifier.id}]`; + case "number": + return String(key.name); + default: + return String(key.name ?? key.kind); + } +} + +function printPattern(pattern) { + switch (pattern.kind) { + case "ArrayPattern": + return `[${pattern.items.map((item) => (item.kind === "Hole" ? "" : item.kind === "Spread" ? `...$${item.place.identifier.id}` : `$${item.identifier.id}`)).join(", ")}]`; + case "ObjectPattern": + return `{${pattern.properties.map((p) => p.kind === "Spread" ? `...$${p.place.identifier.id}` : `${printObjectPropertyKey(p.key)}: $${p.place.identifier.id}`).join(", ")}}`; + default: + return String(pattern); + } +} + +function printPlaceOrSpread(ps) { + if (ps.kind === "Identifier") return `$${ps.identifier.id}`; + if (ps.kind === "Spread") return `...$${ps.place.identifier.id}`; + return ""; +} + +function printInstructionValueFields(value, depth) { + const d = depth; + const lines = []; + const kind = value.kind; + + switch (kind) { + case "LoadLocal": + lines.push(`${indent(d)}LoadLocal {`); + lines.push(`${indent(d + 1)}place: $${value.place.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "LoadContext": + lines.push(`${indent(d)}LoadContext {`); + lines.push(`${indent(d + 1)}place: $${value.place.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "DeclareLocal": + lines.push(`${indent(d)}DeclareLocal {`); + lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${indent(d)}}`); + break; + case "DeclareContext": + lines.push(`${indent(d)}DeclareContext {`); + lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${indent(d)}}`); + break; + case "StoreLocal": + lines.push(`${indent(d)}StoreLocal {`); + lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "StoreContext": + lines.push(`${indent(d)}StoreContext {`); + lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${indent(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "Destructure": + lines.push(`${indent(d)}Destructure {`); + lines.push(`${indent(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${indent(d + 1)}lvalue.pattern: ${printPattern(value.lvalue.pattern)}` + ); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "Primitive": + lines.push(`${indent(d)}Primitive {`); + lines.push( + `${indent(d + 1)}value: ${value.value === undefined ? "undefined" : JSON.stringify(value.value)}` + ); + lines.push(`${indent(d)}}`); + break; + case "JSXText": + lines.push(`${indent(d)}JSXText {`); + lines.push(`${indent(d + 1)}value: ${JSON.stringify(value.value)}`); + lines.push(`${indent(d)}}`); + break; + case "BinaryExpression": + lines.push(`${indent(d)}BinaryExpression {`); + lines.push(`${indent(d + 1)}operator: ${value.operator}`); + lines.push(`${indent(d + 1)}left: $${value.left.identifier.id}`); + lines.push(`${indent(d + 1)}right: $${value.right.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "UnaryExpression": + lines.push(`${indent(d)}UnaryExpression {`); + lines.push(`${indent(d + 1)}operator: ${value.operator}`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "CallExpression": + lines.push(`${indent(d)}CallExpression {`); + lines.push(`${indent(d + 1)}callee: $${value.callee.identifier.id}`); + lines.push( + `${indent(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]` + ); + lines.push(`${indent(d)}}`); + break; + case "MethodCall": + lines.push(`${indent(d)}MethodCall {`); + lines.push( + `${indent(d + 1)}receiver: $${value.receiver.identifier.id}` + ); + lines.push( + `${indent(d + 1)}property: $${value.property.identifier.id}` + ); + lines.push( + `${indent(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]` + ); + lines.push(`${indent(d)}}`); + break; + case "NewExpression": + lines.push(`${indent(d)}NewExpression {`); + lines.push(`${indent(d + 1)}callee: $${value.callee.identifier.id}`); + lines.push( + `${indent(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]` + ); + lines.push(`${indent(d)}}`); + break; + case "ObjectExpression": + lines.push(`${indent(d)}ObjectExpression {`); + if (value.properties != null) { + lines.push(`${indent(d + 1)}properties:`); + for (const prop of value.properties) { + if (prop.kind === "ObjectProperty") { + lines.push( + `${indent(d + 2)}${printObjectPropertyKey(prop.key)}: $${prop.place.identifier.id}` + ); + } else { + lines.push(`${indent(d + 2)}...$${prop.place.identifier.id}`); + } + } + } else { + lines.push(`${indent(d + 1)}properties: null`); + } + lines.push(`${indent(d)}}`); + break; + case "ArrayExpression": + lines.push(`${indent(d)}ArrayExpression {`); + lines.push( + `${indent(d + 1)}elements: [${value.elements.map((e) => (e.kind === "Hole" ? "" : e.kind === "Spread" ? `...$${e.place.identifier.id}` : `$${e.identifier.id}`)).join(", ")}]` + ); + lines.push(`${indent(d)}}`); + break; + case "PropertyLoad": + lines.push(`${indent(d)}PropertyLoad {`); + lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${indent(d + 1)}property: ${value.property}`); + lines.push(`${indent(d)}}`); + break; + case "PropertyStore": + lines.push(`${indent(d)}PropertyStore {`); + lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${indent(d + 1)}property: ${value.property}`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "PropertyDelete": + lines.push(`${indent(d)}PropertyDelete {`); + lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${indent(d + 1)}property: ${value.property}`); + lines.push(`${indent(d)}}`); + break; + case "ComputedLoad": + lines.push(`${indent(d)}ComputedLoad {`); + lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`); + lines.push( + `${indent(d + 1)}property: $${value.property.identifier.id}` + ); + lines.push(`${indent(d)}}`); + break; + case "ComputedStore": + lines.push(`${indent(d)}ComputedStore {`); + lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`); + lines.push( + `${indent(d + 1)}property: $${value.property.identifier.id}` + ); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "ComputedDelete": + lines.push(`${indent(d)}ComputedDelete {`); + lines.push(`${indent(d + 1)}object: $${value.object.identifier.id}`); + lines.push( + `${indent(d + 1)}property: $${value.property.identifier.id}` + ); + lines.push(`${indent(d)}}`); + break; + case "LoadGlobal": { + lines.push(`${indent(d)}LoadGlobal {`); + const b = value.binding; + lines.push(`${indent(d + 1)}binding.kind: ${b.kind}`); + lines.push(`${indent(d + 1)}binding.name: ${b.name}`); + if (b.module != null) { + lines.push(`${indent(d + 1)}binding.module: ${b.module}`); + } + if (b.imported != null) { + lines.push(`${indent(d + 1)}binding.imported: ${b.imported}`); + } + lines.push(`${indent(d)}}`); + break; + } + case "StoreGlobal": + lines.push(`${indent(d)}StoreGlobal {`); + lines.push(`${indent(d + 1)}name: ${value.name}`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "TypeCastExpression": + lines.push(`${indent(d)}TypeCastExpression {`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d + 1)}type: ${formatType(value.type)}`); + lines.push(`${indent(d)}}`); + break; + case "JsxExpression": { + lines.push(`${indent(d)}JsxExpression {`); + if (value.tag.kind === "Identifier") { + lines.push(`${indent(d + 1)}tag: $${value.tag.identifier.id}`); + } else { + lines.push(`${indent(d + 1)}tag: "${value.tag.name}"`); + } + lines.push(`${indent(d + 1)}props:`); + for (const attr of value.props) { + if (attr.kind === "JsxAttribute") { + lines.push( + `${indent(d + 2)}${attr.name}: $${attr.place.identifier.id}` + ); + } else { + lines.push( + `${indent(d + 2)}...$${attr.argument.identifier.id}` + ); + } + } + if (value.children != null) { + lines.push( + `${indent(d + 1)}children: [${value.children.map((c) => `$${c.identifier.id}`).join(", ")}]` + ); + } else { + lines.push(`${indent(d + 1)}children: null`); + } + lines.push(`${indent(d)}}`); + break; + } + case "JsxFragment": + lines.push(`${indent(d)}JsxFragment {`); + lines.push( + `${indent(d + 1)}children: [${value.children.map((c) => `$${c.identifier.id}`).join(", ")}]` + ); + lines.push(`${indent(d)}}`); + break; + case "FunctionExpression": + case "ObjectMethod": { + const label = + kind === "FunctionExpression" ? "FunctionExpression" : "ObjectMethod"; + lines.push(`${indent(d)}${label} {`); + if (kind === "FunctionExpression") { + lines.push( + `${indent(d + 1)}name: ${value.name != null ? JSON.stringify(value.name) : "null"}` + ); + } + lines.push( + `${indent(d + 1)}loweredFunc.id: ${value.loweredFunc.func.id ?? "null"}` + ); + // context + const ctx = value.loweredFunc.func.context; + lines.push( + `${indent(d + 1)}context: [${ctx.map((c) => `$${c.identifier.id}`).join(", ")}]` + ); + // aliasing effects + const ae = value.loweredFunc.func.aliasingEffects; + lines.push( + `${indent(d + 1)}aliasingEffects: ${ae != null ? `[${ae.length} effects]` : "null"}` + ); + lines.push(`${indent(d)}}`); + break; + } + case "TaggedTemplateExpression": + lines.push(`${indent(d)}TaggedTemplateExpression {`); + lines.push(`${indent(d + 1)}tag: $${value.tag.identifier.id}`); + lines.push(`${indent(d + 1)}value.raw: ${JSON.stringify(value.value.raw)}`); + lines.push(`${indent(d)}}`); + break; + case "TemplateLiteral": + lines.push(`${indent(d)}TemplateLiteral {`); + lines.push( + `${indent(d + 1)}quasis: [${value.quasis.map((q) => JSON.stringify(q.raw)).join(", ")}]` + ); + lines.push( + `${indent(d + 1)}subexprs: [${value.subexprs.map((s) => `$${s.identifier.id}`).join(", ")}]` + ); + lines.push(`${indent(d)}}`); + break; + case "RegExpLiteral": + lines.push(`${indent(d)}RegExpLiteral {`); + lines.push(`${indent(d + 1)}pattern: ${value.pattern}`); + lines.push(`${indent(d + 1)}flags: ${value.flags}`); + lines.push(`${indent(d)}}`); + break; + case "MetaProperty": + lines.push(`${indent(d)}MetaProperty {`); + lines.push(`${indent(d + 1)}meta: ${value.meta}`); + lines.push(`${indent(d + 1)}property: ${value.property}`); + lines.push(`${indent(d)}}`); + break; + case "Await": + lines.push(`${indent(d)}Await {`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "GetIterator": + lines.push(`${indent(d)}GetIterator {`); + lines.push( + `${indent(d + 1)}collection: $${value.collection.identifier.id}` + ); + lines.push(`${indent(d)}}`); + break; + case "IteratorNext": + lines.push(`${indent(d)}IteratorNext {`); + lines.push( + `${indent(d + 1)}iterator: $${value.iterator.identifier.id}` + ); + lines.push( + `${indent(d + 1)}collection: $${value.collection.identifier.id}` + ); + lines.push(`${indent(d)}}`); + break; + case "NextPropertyOf": + lines.push(`${indent(d)}NextPropertyOf {`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "PostfixUpdate": + lines.push(`${indent(d)}PostfixUpdate {`); + lines.push(`${indent(d + 1)}lvalue: $${value.lvalue.identifier.id}`); + lines.push(`${indent(d + 1)}operation: ${value.operation}`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "PrefixUpdate": + lines.push(`${indent(d)}PrefixUpdate {`); + lines.push(`${indent(d + 1)}lvalue: $${value.lvalue.identifier.id}`); + lines.push(`${indent(d + 1)}operation: ${value.operation}`); + lines.push(`${indent(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${indent(d)}}`); + break; + case "Debugger": + lines.push(`${indent(d)}Debugger {}`); + break; + case "StartMemoize": + lines.push(`${indent(d)}StartMemoize {`); + lines.push(`${indent(d + 1)}manualMemoId: ${value.manualMemoId}`); + lines.push(`${indent(d + 1)}deps: ${value.deps != null ? `[${value.deps.length} deps]` : "null"}`); + lines.push(`${indent(d)}}`); + break; + case "FinishMemoize": + lines.push(`${indent(d)}FinishMemoize {`); + lines.push(`${indent(d + 1)}manualMemoId: ${value.manualMemoId}`); + lines.push(`${indent(d + 1)}decl: $${value.decl.identifier.id}`); + lines.push(`${indent(d + 1)}pruned: ${value.pruned === true}`); + lines.push(`${indent(d)}}`); + break; + case "UnsupportedNode": + lines.push(`${indent(d)}UnsupportedNode {`); + lines.push( + `${indent(d + 1)}type: ${value.node != null ? value.node.type : "unknown"}` + ); + lines.push(`${indent(d)}}`); + break; + // Reactive-only value types that may appear: + case "LogicalExpression": + lines.push(`${indent(d)}LogicalExpression {`); + lines.push(`${indent(d + 1)}operator: ${value.operator}`); + lines.push(`${indent(d)}}`); + break; + case "ConditionalExpression": + lines.push(`${indent(d)}ConditionalExpression {}`); + break; + case "SequenceExpression": + lines.push(`${indent(d)}SequenceExpression {}`); + break; + case "OptionalExpression": + lines.push(`${indent(d)}OptionalExpression {`); + lines.push(`${indent(d + 1)}optional: ${value.optional}`); + lines.push(`${indent(d)}}`); + break; + default: + lines.push(`${indent(d)}${kind} {}`); + break; + } + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Instruction printing +// --------------------------------------------------------------------------- + +function printInstruction(instr, depth) { + const lines = []; + lines.push(`${indent(depth)}[${instr.id}] Instruction {`); + const d = depth + 1; + lines.push(`${indent(d)}id: ${instr.id}`); + // lvalue + lines.push(`${indent(d)}lvalue:`); + lines.push(printPlaceInline(instr.lvalue, d + 1)); + // value + lines.push(`${indent(d)}value:`); + lines.push(printInstructionValueFields(instr.value, d + 1)); + // effects + if (instr.effects != null) { + lines.push(`${indent(d)}effects: [${instr.effects.length} effects]`); + } else { + lines.push(`${indent(d)}effects: null`); + } + lines.push(`${indent(d)}loc: ${formatLoc(instr.loc)}`); + lines.push(`${indent(depth)}}`); + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Terminal printing +// --------------------------------------------------------------------------- + +function printTerminal(terminal, depth) { + const lines = []; + const d = depth; + const kind = terminal.kind; + lines.push(`${indent(d)}${terminalName(kind)} {`); + lines.push(`${indent(d + 1)}id: ${terminal.id}`); + + switch (kind) { + case "if": + lines.push(`${indent(d + 1)}test:`); + lines.push(printPlaceInline(terminal.test, d + 2)); + lines.push(`${indent(d + 1)}consequent: bb${terminal.consequent}`); + lines.push(`${indent(d + 1)}alternate: bb${terminal.alternate}`); + lines.push( + `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}` + ); + break; + case "branch": + lines.push(`${indent(d + 1)}test:`); + lines.push(printPlaceInline(terminal.test, d + 2)); + lines.push(`${indent(d + 1)}consequent: bb${terminal.consequent}`); + lines.push(`${indent(d + 1)}alternate: bb${terminal.alternate}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "return": + lines.push(`${indent(d + 1)}returnVariant: ${terminal.returnVariant}`); + lines.push(`${indent(d + 1)}value:`); + lines.push(printPlaceInline(terminal.value, d + 2)); + if (terminal.effects != null) { + lines.push( + `${indent(d + 1)}effects: [${terminal.effects.length} effects]` + ); + } else { + lines.push(`${indent(d + 1)}effects: null`); + } + break; + case "throw": + lines.push(`${indent(d + 1)}value:`); + lines.push(printPlaceInline(terminal.value, d + 2)); + break; + case "goto": + lines.push(`${indent(d + 1)}block: bb${terminal.block}`); + lines.push(`${indent(d + 1)}variant: ${terminal.variant}`); + break; + case "switch": + lines.push(`${indent(d + 1)}test:`); + lines.push(printPlaceInline(terminal.test, d + 2)); + lines.push(`${indent(d + 1)}cases:`); + for (const c of terminal.cases) { + if (c.test != null) { + lines.push(`${indent(d + 2)}case $${c.test.identifier.id}: bb${c.block}`); + } else { + lines.push(`${indent(d + 2)}default: bb${c.block}`); + } + } + lines.push( + `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}` + ); + break; + case "do-while": + lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`); + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "while": + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push( + `${indent(d + 1)}loop: ${terminal.loop != null ? `bb${terminal.loop}` : "null"}` + ); + lines.push( + `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}` + ); + break; + case "for": + lines.push(`${indent(d + 1)}init: bb${terminal.init}`); + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push( + `${indent(d + 1)}update: ${terminal.update != null ? `bb${terminal.update}` : "null"}` + ); + lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "for-of": + lines.push(`${indent(d + 1)}init: bb${terminal.init}`); + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "for-in": + lines.push(`${indent(d + 1)}init: bb${terminal.init}`); + lines.push(`${indent(d + 1)}loop: bb${terminal.loop}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "logical": + lines.push(`${indent(d + 1)}operator: ${terminal.operator}`); + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "ternary": + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "optional": + lines.push(`${indent(d + 1)}optional: ${terminal.optional}`); + lines.push(`${indent(d + 1)}test: bb${terminal.test}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "label": + lines.push(`${indent(d + 1)}block: bb${terminal.block}`); + lines.push( + `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}` + ); + break; + case "sequence": + lines.push(`${indent(d + 1)}block: bb${terminal.block}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "maybe-throw": + lines.push(`${indent(d + 1)}continuation: bb${terminal.continuation}`); + lines.push( + `${indent(d + 1)}handler: ${terminal.handler != null ? `bb${terminal.handler}` : "null"}` + ); + if (terminal.effects != null) { + lines.push( + `${indent(d + 1)}effects: [${terminal.effects.length} effects]` + ); + } else { + lines.push(`${indent(d + 1)}effects: null`); + } + break; + case "try": + lines.push(`${indent(d + 1)}block: bb${terminal.block}`); + if (terminal.handlerBinding != null) { + lines.push(`${indent(d + 1)}handlerBinding:`); + lines.push(printPlaceInline(terminal.handlerBinding, d + 2)); + } else { + lines.push(`${indent(d + 1)}handlerBinding: null`); + } + lines.push(`${indent(d + 1)}handler: bb${terminal.handler}`); + lines.push( + `${indent(d + 1)}fallthrough: ${terminal.fallthrough != null ? `bb${terminal.fallthrough}` : "null"}` + ); + break; + case "scope": + lines.push(`${indent(d + 1)}scope: @${terminal.scope.id}`); + lines.push(`${indent(d + 1)}block: bb${terminal.block}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "pruned-scope": + lines.push(`${indent(d + 1)}scope: @${terminal.scope.id}`); + lines.push(`${indent(d + 1)}block: bb${terminal.block}`); + lines.push(`${indent(d + 1)}fallthrough: bb${terminal.fallthrough}`); + break; + case "unreachable": + break; + case "unsupported": + break; + default: + break; + } + + lines.push(`${indent(d + 1)}loc: ${formatLoc(terminal.loc)}`); + lines.push(`${indent(d)}}`); + return lines.join("\n"); +} + +function terminalName(kind) { + const names = { + if: "If", + branch: "Branch", + return: "Return", + throw: "Throw", + goto: "Goto", + switch: "Switch", + "do-while": "DoWhile", + while: "While", + for: "For", + "for-of": "ForOf", + "for-in": "ForIn", + logical: "Logical", + ternary: "Ternary", + optional: "Optional", + label: "Label", + sequence: "Sequence", + "maybe-throw": "MaybeThrow", + try: "Try", + scope: "Scope", + "pruned-scope": "PrunedScope", + unreachable: "Unreachable", + unsupported: "Unsupported", + }; + return names[kind] ?? kind; +} + +// --------------------------------------------------------------------------- +// Phi printing +// --------------------------------------------------------------------------- + +function printPhi(phi, depth) { + const lines = []; + lines.push(`${indent(depth)}Phi {`); + lines.push(`${indent(depth + 1)}place: $${phi.place.identifier.id}`); + lines.push(`${indent(depth + 1)}operands:`); + // phi.operands is a Map + const sortedOperands = [...phi.operands].sort((a, b) => a[0] - b[0]); + for (const [blockId, place] of sortedOperands) { + lines.push( + `${indent(depth + 2)}bb${blockId}: $${place.identifier.id}` + ); + } + lines.push(`${indent(depth)}}`); + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Main function printer +// --------------------------------------------------------------------------- + +function printHIRFunction(fn, functionIndex, outlinedCollector) { + const lines = []; + const d0 = 0; + const d1 = 1; + const d2 = 2; + + lines.push(`${indent(d0)}Function #${functionIndex}:`); + + // id + lines.push( + `${indent(d1)}id: ${fn.id != null ? JSON.stringify(fn.id) : "null"}` + ); + + // params + lines.push(`${indent(d1)}params:`); + for (let i = 0; i < fn.params.length; i++) { + const param = fn.params[i]; + if (param.kind === "Identifier") { + lines.push(`${indent(d2)}[${i}]`); + lines.push(printPlaceInline(param, d2 + 1)); + } else { + // Spread + lines.push(`${indent(d2)}[${i}] ...`); + lines.push(printPlaceInline(param.place, d2 + 1)); + } + } + + // returns + lines.push(`${indent(d1)}returns:`); + lines.push(printPlaceInline(fn.returns, d2)); + + // returnTypeAnnotation + if (fn.returnTypeAnnotation != null) { + lines.push(`${indent(d1)}returnTypeAnnotation: ${JSON.stringify(fn.returnTypeAnnotation)}`); + } else { + lines.push(`${indent(d1)}returnTypeAnnotation: null`); + } + + // context + if (fn.context.length > 0) { + lines.push(`${indent(d1)}context:`); + for (const ctx of fn.context) { + lines.push(printPlaceInline(ctx, d2)); + } + } else { + lines.push(`${indent(d1)}context: []`); + } + + // directives + if (fn.directives.length > 0) { + lines.push( + `${indent(d1)}directives: [${fn.directives.map((d) => JSON.stringify(d)).join(", ")}]` + ); + } else { + lines.push(`${indent(d1)}directives: []`); + } + + // generator / async + lines.push(`${indent(d1)}generator: ${fn.generator}`); + lines.push(`${indent(d1)}async: ${fn.async}`); + + // aliasingEffects + if (fn.aliasingEffects != null) { + lines.push( + `${indent(d1)}aliasingEffects: [${fn.aliasingEffects.length} effects]` + ); + } else { + lines.push(`${indent(d1)}aliasingEffects: null`); + } + + // Collect all identifiers from the function + const identifiers = new Map(); + collectIdentifiers(fn, identifiers); + + lines.push(""); + lines.push(`${indent(d1)}Identifiers:`); + const sortedIds = [...identifiers.entries()].sort((a, b) => a[0] - b[0]); + for (const [, identifier] of sortedIds) { + lines.push(printIdentifierEntry(identifier, d2)); + } + + // Blocks (in order from body.blocks, which is RPO) + lines.push(""); + lines.push(`${indent(d1)}Blocks:`); + for (const [blockId, block] of fn.body.blocks) { + lines.push(`${indent(d2)}bb${blockId} (${block.kind}):`); + const d3 = d2 + 1; + + // preds + const preds = [...block.preds].sort((a, b) => a - b); + lines.push(`${indent(d3)}preds: [${preds.map((p) => `bb${p}`).join(", ")}]`); + + // phis + if (block.phis.size > 0) { + lines.push(`${indent(d3)}phis:`); + for (const phi of block.phis) { + lines.push(printPhi(phi, d3 + 1)); + } + } else { + lines.push(`${indent(d3)}phis: []`); + } + + // instructions + lines.push(`${indent(d3)}instructions:`); + for (const instr of block.instructions) { + lines.push(printInstruction(instr, d3 + 1)); + // Collect outlined functions + if ( + instr.value.kind === "FunctionExpression" || + instr.value.kind === "ObjectMethod" + ) { + outlinedCollector.push(instr.value.loweredFunc.func); + } + } + + // terminal + lines.push(`${indent(d3)}terminal:`); + lines.push(printTerminal(block.terminal, d3 + 1)); + } + + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Identifier collection +// --------------------------------------------------------------------------- + +function collectIdentifiers(fn, map) { + // From params + for (const param of fn.params) { + if (param.kind === "Identifier") { + addIdentifier(map, param.identifier); + } else { + addIdentifier(map, param.place.identifier); + } + } + + // returns + addIdentifier(map, fn.returns.identifier); + + // context + for (const ctx of fn.context) { + addIdentifier(map, ctx.identifier); + } + + // From blocks + for (const [, block] of fn.body.blocks) { + // phis + for (const phi of block.phis) { + addIdentifier(map, phi.place.identifier); + for (const [, place] of phi.operands) { + addIdentifier(map, place.identifier); + } + } + + // instructions + for (const instr of block.instructions) { + addIdentifier(map, instr.lvalue.identifier); + collectIdentifiersFromValue(instr.value, map); + } + + // terminal + collectIdentifiersFromTerminal(block.terminal, map); + } +} + +function addIdentifier(map, identifier) { + if (!map.has(identifier.id)) { + map.set(identifier.id, identifier); + } +} + +function collectIdentifiersFromPlace(place, map) { + if (place != null) { + addIdentifier(map, place.identifier); + } +} + +function collectIdentifiersFromValue(value, map) { + if (value == null) return; + switch (value.kind) { + case "LoadLocal": + case "LoadContext": + collectIdentifiersFromPlace(value.place, map); + break; + case "DeclareLocal": + case "DeclareContext": + collectIdentifiersFromPlace(value.lvalue.place, map); + break; + case "StoreLocal": + case "StoreContext": + collectIdentifiersFromPlace(value.lvalue.place, map); + collectIdentifiersFromPlace(value.value, map); + break; + case "Destructure": + collectIdentifiersFromPattern(value.lvalue.pattern, map); + collectIdentifiersFromPlace(value.value, map); + break; + case "BinaryExpression": + collectIdentifiersFromPlace(value.left, map); + collectIdentifiersFromPlace(value.right, map); + break; + case "UnaryExpression": + collectIdentifiersFromPlace(value.value, map); + break; + case "CallExpression": + case "NewExpression": + collectIdentifiersFromPlace(value.callee, map); + for (const arg of value.args) { + if (arg.kind === "Identifier") collectIdentifiersFromPlace(arg, map); + else if (arg.kind === "Spread") + collectIdentifiersFromPlace(arg.place, map); + } + break; + case "MethodCall": + collectIdentifiersFromPlace(value.receiver, map); + collectIdentifiersFromPlace(value.property, map); + for (const arg of value.args) { + if (arg.kind === "Identifier") collectIdentifiersFromPlace(arg, map); + else if (arg.kind === "Spread") + collectIdentifiersFromPlace(arg.place, map); + } + break; + case "ObjectExpression": + if (value.properties != null) { + for (const prop of value.properties) { + if (prop.kind === "ObjectProperty") { + collectIdentifiersFromPlace(prop.place, map); + if (prop.key.kind === "computed") + collectIdentifiersFromPlace(prop.key.name, map); + } else { + collectIdentifiersFromPlace(prop.place, map); + } + } + } + break; + case "ArrayExpression": + for (const el of value.elements) { + if (el.kind === "Identifier") collectIdentifiersFromPlace(el, map); + else if (el.kind === "Spread") + collectIdentifiersFromPlace(el.place, map); + } + break; + case "PropertyLoad": + case "PropertyDelete": + collectIdentifiersFromPlace(value.object, map); + break; + case "PropertyStore": + collectIdentifiersFromPlace(value.object, map); + collectIdentifiersFromPlace(value.value, map); + break; + case "ComputedLoad": + case "ComputedDelete": + collectIdentifiersFromPlace(value.object, map); + collectIdentifiersFromPlace(value.property, map); + break; + case "ComputedStore": + collectIdentifiersFromPlace(value.object, map); + collectIdentifiersFromPlace(value.property, map); + collectIdentifiersFromPlace(value.value, map); + break; + case "StoreGlobal": + collectIdentifiersFromPlace(value.value, map); + break; + case "TypeCastExpression": + collectIdentifiersFromPlace(value.value, map); + break; + case "JsxExpression": + if (value.tag.kind === "Identifier") + collectIdentifiersFromPlace(value.tag, map); + for (const attr of value.props) { + if (attr.kind === "JsxAttribute") + collectIdentifiersFromPlace(attr.place, map); + else collectIdentifiersFromPlace(attr.argument, map); + } + if (value.children != null) { + for (const child of value.children) + collectIdentifiersFromPlace(child, map); + } + break; + case "JsxFragment": + for (const child of value.children) + collectIdentifiersFromPlace(child, map); + break; + case "FunctionExpression": + case "ObjectMethod": + // context of lowered func + for (const ctx of value.loweredFunc.func.context) { + collectIdentifiersFromPlace(ctx, map); + } + break; + case "TaggedTemplateExpression": + collectIdentifiersFromPlace(value.tag, map); + break; + case "TemplateLiteral": + for (const s of value.subexprs) collectIdentifiersFromPlace(s, map); + break; + case "Await": + collectIdentifiersFromPlace(value.value, map); + break; + case "GetIterator": + collectIdentifiersFromPlace(value.collection, map); + break; + case "IteratorNext": + collectIdentifiersFromPlace(value.iterator, map); + collectIdentifiersFromPlace(value.collection, map); + break; + case "NextPropertyOf": + collectIdentifiersFromPlace(value.value, map); + break; + case "PostfixUpdate": + case "PrefixUpdate": + collectIdentifiersFromPlace(value.lvalue, map); + collectIdentifiersFromPlace(value.value, map); + break; + case "FinishMemoize": + collectIdentifiersFromPlace(value.decl, map); + break; + case "StartMemoize": + if (value.deps != null) { + for (const dep of value.deps) { + if (dep.root.kind === "NamedLocal") { + collectIdentifiersFromPlace(dep.root.value, map); + } + } + } + break; + default: + break; + } +} + +function collectIdentifiersFromPattern(pattern, map) { + switch (pattern.kind) { + case "ArrayPattern": + for (const item of pattern.items) { + if (item.kind === "Identifier") collectIdentifiersFromPlace(item, map); + else if (item.kind === "Spread") + collectIdentifiersFromPlace(item.place, map); + } + break; + case "ObjectPattern": + for (const prop of pattern.properties) { + if (prop.kind === "ObjectProperty") { + collectIdentifiersFromPlace(prop.place, map); + if (prop.key.kind === "computed") + collectIdentifiersFromPlace(prop.key.name, map); + } else { + collectIdentifiersFromPlace(prop.place, map); + } + } + break; + } +} + +function collectIdentifiersFromTerminal(terminal, map) { + switch (terminal.kind) { + case "if": + case "branch": + collectIdentifiersFromPlace(terminal.test, map); + break; + case "return": + collectIdentifiersFromPlace(terminal.value, map); + break; + case "throw": + collectIdentifiersFromPlace(terminal.value, map); + break; + case "switch": + collectIdentifiersFromPlace(terminal.test, map); + for (const c of terminal.cases) { + if (c.test != null) collectIdentifiersFromPlace(c.test, map); + } + break; + case "try": + if (terminal.handlerBinding != null) + collectIdentifiersFromPlace(terminal.handlerBinding, map); + break; + default: + break; + } +} diff --git a/compiler/scripts/debug-print-reactive.mjs b/compiler/scripts/debug-print-reactive.mjs new file mode 100644 index 000000000000..18f2fc0fa1fd --- /dev/null +++ b/compiler/scripts/debug-print-reactive.mjs @@ -0,0 +1,1015 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Debug ReactiveFunction printer for the Rust port testing infrastructure. + * + * Custom printer that walks the ReactiveFunction tree structure and prints + * every field of every scope, instruction, terminal, and reactive value node. + * + * This does NOT delegate to printReactiveFunctionWithOutlined() โ€” it is a + * standalone walker that produces a detailed, deterministic representation + * suitable for cross-compiler comparison between the TS and Rust implementations. + * + * @param {Function} _printReactiveFunctionWithOutlined - Unused (kept for API compat) + * @param {object} reactiveFunction - The ReactiveFunction to print + * @returns {string} The debug representation + */ +export function debugPrintReactive( + _printReactiveFunctionWithOutlined, + reactiveFunction +) { + const outlined = []; + const result = printReactiveFunction(reactiveFunction, 0, outlined); + const parts = [result]; + for (let i = 0; i < outlined.length; i++) { + parts.push(printReactiveFunction(outlined[i], i + 1, outlined)); + } + return parts.join("\n\n"); +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function ind(depth) { + return " ".repeat(depth); +} + +function formatLoc(loc) { + if (loc == null || typeof loc === "symbol") { + return "generated"; + } + return `${loc.start.line}:${loc.start.column}-${loc.end.line}:${loc.end.column}`; +} + +function formatEffect(effect) { + return String(effect); +} + +function formatType(type) { + if (type == null) return "Type"; + switch (type.kind) { + case "Type": + return "Type"; + case "Primitive": + return "Primitive"; + case "Object": + return type.shapeId != null ? `Object<${type.shapeId}>` : "Object"; + case "Function": { + const ret = formatType(type.return); + const base = + type.shapeId != null ? `Function<${type.shapeId}>` : "Function"; + return ret !== "Type" ? `${base}():${ret}` : base; + } + case "Poly": + return "Poly"; + case "Phi": { + const ops = type.operands.map(formatType).join(", "); + return `Phi(${ops})`; + } + case "Property": { + const objType = formatType(type.objectType); + return `Property(${objType}.${type.objectName})`; + } + case "ObjectMethod": + return "ObjectMethod"; + default: + return "Type"; + } +} + +function formatIdentifierName(name) { + if (name == null) return "null"; + if (typeof name === "object" && name.value != null) { + return JSON.stringify(name.value); + } + return JSON.stringify(String(name)); +} + +function formatMutableRange(range) { + if (range == null) return "[0:0]"; + return `[${range.start}:${range.end}]`; +} + +function formatScopeId(scope) { + if (scope == null) return "null"; + return `@${scope.id}`; +} + +function formatDeclarationId(id) { + if (id == null) return "null"; + return String(id); +} + +// --------------------------------------------------------------------------- +// Place printing +// --------------------------------------------------------------------------- + +function printPlaceInline(place, depth) { + const id = place.identifier; + return [ + `${ind(depth)}Place {`, + `${ind(depth + 1)}identifier: $${id.id}`, + `${ind(depth + 1)}effect: ${formatEffect(place.effect)}`, + `${ind(depth + 1)}reactive: ${place.reactive}`, + `${ind(depth + 1)}loc: ${formatLoc(place.loc)}`, + `${ind(depth)}}`, + ].join("\n"); +} + +// --------------------------------------------------------------------------- +// Object property key +// --------------------------------------------------------------------------- + +function printObjectPropertyKey(key) { + switch (key.kind) { + case "identifier": + return key.name; + case "string": + return `"${key.name}"`; + case "computed": + return `[$${key.name.identifier.id}]`; + case "number": + return String(key.name); + default: + return String(key.name ?? key.kind); + } +} + +function printPlaceOrSpread(ps) { + if (ps.kind === "Identifier") return `$${ps.identifier.id}`; + if (ps.kind === "Spread") return `...$${ps.place.identifier.id}`; + return ""; +} + +function printPattern(pattern) { + switch (pattern.kind) { + case "ArrayPattern": + return `[${pattern.items.map((item) => (item.kind === "Hole" ? "" : item.kind === "Spread" ? `...$${item.place.identifier.id}` : `$${item.identifier.id}`)).join(", ")}]`; + case "ObjectPattern": + return `{${pattern.properties.map((p) => p.kind === "Spread" ? `...$${p.place.identifier.id}` : `${printObjectPropertyKey(p.key)}: $${p.place.identifier.id}`).join(", ")}}`; + default: + return String(pattern); + } +} + +// --------------------------------------------------------------------------- +// InstructionValue printing (shared with HIR printer) +// --------------------------------------------------------------------------- + +function printInstructionValueFields(value, depth) { + const d = depth; + const lines = []; + const kind = value.kind; + + switch (kind) { + case "LoadLocal": + lines.push(`${ind(d)}LoadLocal {`); + lines.push(`${ind(d + 1)}place: $${value.place.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "LoadContext": + lines.push(`${ind(d)}LoadContext {`); + lines.push(`${ind(d + 1)}place: $${value.place.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "DeclareLocal": + lines.push(`${ind(d)}DeclareLocal {`); + lines.push(`${ind(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${ind(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${ind(d)}}`); + break; + case "DeclareContext": + lines.push(`${ind(d)}DeclareContext {`); + lines.push(`${ind(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${ind(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${ind(d)}}`); + break; + case "StoreLocal": + lines.push(`${ind(d)}StoreLocal {`); + lines.push(`${ind(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${ind(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "StoreContext": + lines.push(`${ind(d)}StoreContext {`); + lines.push(`${ind(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${ind(d + 1)}lvalue.place: $${value.lvalue.place.identifier.id}` + ); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "Destructure": + lines.push(`${ind(d)}Destructure {`); + lines.push(`${ind(d + 1)}lvalue.kind: ${value.lvalue.kind}`); + lines.push( + `${ind(d + 1)}lvalue.pattern: ${printPattern(value.lvalue.pattern)}` + ); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "Primitive": + lines.push(`${ind(d)}Primitive {`); + lines.push( + `${ind(d + 1)}value: ${value.value === undefined ? "undefined" : JSON.stringify(value.value)}` + ); + lines.push(`${ind(d)}}`); + break; + case "JSXText": + lines.push(`${ind(d)}JSXText {`); + lines.push(`${ind(d + 1)}value: ${JSON.stringify(value.value)}`); + lines.push(`${ind(d)}}`); + break; + case "BinaryExpression": + lines.push(`${ind(d)}BinaryExpression {`); + lines.push(`${ind(d + 1)}operator: ${value.operator}`); + lines.push(`${ind(d + 1)}left: $${value.left.identifier.id}`); + lines.push(`${ind(d + 1)}right: $${value.right.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "UnaryExpression": + lines.push(`${ind(d)}UnaryExpression {`); + lines.push(`${ind(d + 1)}operator: ${value.operator}`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "CallExpression": + lines.push(`${ind(d)}CallExpression {`); + lines.push(`${ind(d + 1)}callee: $${value.callee.identifier.id}`); + lines.push( + `${ind(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]` + ); + lines.push(`${ind(d)}}`); + break; + case "MethodCall": + lines.push(`${ind(d)}MethodCall {`); + lines.push(`${ind(d + 1)}receiver: $${value.receiver.identifier.id}`); + lines.push(`${ind(d + 1)}property: $${value.property.identifier.id}`); + lines.push( + `${ind(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]` + ); + lines.push(`${ind(d)}}`); + break; + case "NewExpression": + lines.push(`${ind(d)}NewExpression {`); + lines.push(`${ind(d + 1)}callee: $${value.callee.identifier.id}`); + lines.push( + `${ind(d + 1)}args: [${value.args.map(printPlaceOrSpread).join(", ")}]` + ); + lines.push(`${ind(d)}}`); + break; + case "ObjectExpression": + lines.push(`${ind(d)}ObjectExpression {`); + if (value.properties != null) { + lines.push(`${ind(d + 1)}properties:`); + for (const prop of value.properties) { + if (prop.kind === "ObjectProperty") { + lines.push( + `${ind(d + 2)}${printObjectPropertyKey(prop.key)}: $${prop.place.identifier.id}` + ); + } else { + lines.push(`${ind(d + 2)}...$${prop.place.identifier.id}`); + } + } + } else { + lines.push(`${ind(d + 1)}properties: null`); + } + lines.push(`${ind(d)}}`); + break; + case "ArrayExpression": + lines.push(`${ind(d)}ArrayExpression {`); + lines.push( + `${ind(d + 1)}elements: [${value.elements.map((e) => (e.kind === "Hole" ? "" : e.kind === "Spread" ? `...$${e.place.identifier.id}` : `$${e.identifier.id}`)).join(", ")}]` + ); + lines.push(`${ind(d)}}`); + break; + case "PropertyLoad": + lines.push(`${ind(d)}PropertyLoad {`); + lines.push(`${ind(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${ind(d + 1)}property: ${value.property}`); + lines.push(`${ind(d)}}`); + break; + case "PropertyStore": + lines.push(`${ind(d)}PropertyStore {`); + lines.push(`${ind(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${ind(d + 1)}property: ${value.property}`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "PropertyDelete": + lines.push(`${ind(d)}PropertyDelete {`); + lines.push(`${ind(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${ind(d + 1)}property: ${value.property}`); + lines.push(`${ind(d)}}`); + break; + case "ComputedLoad": + lines.push(`${ind(d)}ComputedLoad {`); + lines.push(`${ind(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${ind(d + 1)}property: $${value.property.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "ComputedStore": + lines.push(`${ind(d)}ComputedStore {`); + lines.push(`${ind(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${ind(d + 1)}property: $${value.property.identifier.id}`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "ComputedDelete": + lines.push(`${ind(d)}ComputedDelete {`); + lines.push(`${ind(d + 1)}object: $${value.object.identifier.id}`); + lines.push(`${ind(d + 1)}property: $${value.property.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "LoadGlobal": { + lines.push(`${ind(d)}LoadGlobal {`); + const b = value.binding; + lines.push(`${ind(d + 1)}binding.kind: ${b.kind}`); + lines.push(`${ind(d + 1)}binding.name: ${b.name}`); + if (b.module != null) { + lines.push(`${ind(d + 1)}binding.module: ${b.module}`); + } + if (b.imported != null) { + lines.push(`${ind(d + 1)}binding.imported: ${b.imported}`); + } + lines.push(`${ind(d)}}`); + break; + } + case "StoreGlobal": + lines.push(`${ind(d)}StoreGlobal {`); + lines.push(`${ind(d + 1)}name: ${value.name}`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "TypeCastExpression": + lines.push(`${ind(d)}TypeCastExpression {`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d + 1)}type: ${formatType(value.type)}`); + lines.push(`${ind(d)}}`); + break; + case "JsxExpression": { + lines.push(`${ind(d)}JsxExpression {`); + if (value.tag.kind === "Identifier") { + lines.push(`${ind(d + 1)}tag: $${value.tag.identifier.id}`); + } else { + lines.push(`${ind(d + 1)}tag: "${value.tag.name}"`); + } + lines.push(`${ind(d + 1)}props:`); + for (const attr of value.props) { + if (attr.kind === "JsxAttribute") { + lines.push( + `${ind(d + 2)}${attr.name}: $${attr.place.identifier.id}` + ); + } else { + lines.push(`${ind(d + 2)}...$${attr.argument.identifier.id}`); + } + } + if (value.children != null) { + lines.push( + `${ind(d + 1)}children: [${value.children.map((c) => `$${c.identifier.id}`).join(", ")}]` + ); + } else { + lines.push(`${ind(d + 1)}children: null`); + } + lines.push(`${ind(d)}}`); + break; + } + case "JsxFragment": + lines.push(`${ind(d)}JsxFragment {`); + lines.push( + `${ind(d + 1)}children: [${value.children.map((c) => `$${c.identifier.id}`).join(", ")}]` + ); + lines.push(`${ind(d)}}`); + break; + case "FunctionExpression": + case "ObjectMethod": { + const label = + kind === "FunctionExpression" ? "FunctionExpression" : "ObjectMethod"; + lines.push(`${ind(d)}${label} {`); + if (kind === "FunctionExpression") { + lines.push( + `${ind(d + 1)}name: ${value.name != null ? JSON.stringify(value.name) : "null"}` + ); + } + lines.push( + `${ind(d + 1)}loweredFunc.id: ${value.loweredFunc.func.id ?? "null"}` + ); + const ctx = value.loweredFunc.func.context; + lines.push( + `${ind(d + 1)}context: [${ctx.map((c) => `$${c.identifier.id}`).join(", ")}]` + ); + const ae = value.loweredFunc.func.aliasingEffects; + lines.push( + `${ind(d + 1)}aliasingEffects: ${ae != null ? `[${ae.length} effects]` : "null"}` + ); + lines.push(`${ind(d)}}`); + break; + } + case "TaggedTemplateExpression": + lines.push(`${ind(d)}TaggedTemplateExpression {`); + lines.push(`${ind(d + 1)}tag: $${value.tag.identifier.id}`); + lines.push( + `${ind(d + 1)}value.raw: ${JSON.stringify(value.value.raw)}` + ); + lines.push(`${ind(d)}}`); + break; + case "TemplateLiteral": + lines.push(`${ind(d)}TemplateLiteral {`); + lines.push( + `${ind(d + 1)}quasis: [${value.quasis.map((q) => JSON.stringify(q.raw)).join(", ")}]` + ); + lines.push( + `${ind(d + 1)}subexprs: [${value.subexprs.map((s) => `$${s.identifier.id}`).join(", ")}]` + ); + lines.push(`${ind(d)}}`); + break; + case "RegExpLiteral": + lines.push(`${ind(d)}RegExpLiteral {`); + lines.push(`${ind(d + 1)}pattern: ${value.pattern}`); + lines.push(`${ind(d + 1)}flags: ${value.flags}`); + lines.push(`${ind(d)}}`); + break; + case "MetaProperty": + lines.push(`${ind(d)}MetaProperty {`); + lines.push(`${ind(d + 1)}meta: ${value.meta}`); + lines.push(`${ind(d + 1)}property: ${value.property}`); + lines.push(`${ind(d)}}`); + break; + case "Await": + lines.push(`${ind(d)}Await {`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "GetIterator": + lines.push(`${ind(d)}GetIterator {`); + lines.push( + `${ind(d + 1)}collection: $${value.collection.identifier.id}` + ); + lines.push(`${ind(d)}}`); + break; + case "IteratorNext": + lines.push(`${ind(d)}IteratorNext {`); + lines.push(`${ind(d + 1)}iterator: $${value.iterator.identifier.id}`); + lines.push( + `${ind(d + 1)}collection: $${value.collection.identifier.id}` + ); + lines.push(`${ind(d)}}`); + break; + case "NextPropertyOf": + lines.push(`${ind(d)}NextPropertyOf {`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "PostfixUpdate": + lines.push(`${ind(d)}PostfixUpdate {`); + lines.push(`${ind(d + 1)}lvalue: $${value.lvalue.identifier.id}`); + lines.push(`${ind(d + 1)}operation: ${value.operation}`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "PrefixUpdate": + lines.push(`${ind(d)}PrefixUpdate {`); + lines.push(`${ind(d + 1)}lvalue: $${value.lvalue.identifier.id}`); + lines.push(`${ind(d + 1)}operation: ${value.operation}`); + lines.push(`${ind(d + 1)}value: $${value.value.identifier.id}`); + lines.push(`${ind(d)}}`); + break; + case "Debugger": + lines.push(`${ind(d)}Debugger {}`); + break; + case "StartMemoize": + lines.push(`${ind(d)}StartMemoize {`); + lines.push(`${ind(d + 1)}manualMemoId: ${value.manualMemoId}`); + lines.push( + `${ind(d + 1)}deps: ${value.deps != null ? `[${value.deps.length} deps]` : "null"}` + ); + lines.push(`${ind(d)}}`); + break; + case "FinishMemoize": + lines.push(`${ind(d)}FinishMemoize {`); + lines.push(`${ind(d + 1)}manualMemoId: ${value.manualMemoId}`); + lines.push(`${ind(d + 1)}decl: $${value.decl.identifier.id}`); + lines.push(`${ind(d + 1)}pruned: ${value.pruned === true}`); + lines.push(`${ind(d)}}`); + break; + case "UnsupportedNode": + lines.push(`${ind(d)}UnsupportedNode {`); + lines.push( + `${ind(d + 1)}type: ${value.node != null ? value.node.type : "unknown"}` + ); + lines.push(`${ind(d)}}`); + break; + default: + lines.push(`${ind(d)}${kind} {}`); + break; + } + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Reactive value printing (tree-structured values) +// --------------------------------------------------------------------------- + +function printReactiveValue(value, depth, outlinedCollector) { + const d = depth; + const lines = []; + + switch (value.kind) { + case "LogicalExpression": + lines.push(`${ind(d)}LogicalExpression {`); + lines.push(`${ind(d + 1)}operator: ${value.operator}`); + lines.push(`${ind(d + 1)}left:`); + lines.push(printReactiveValue(value.left, d + 2, outlinedCollector)); + lines.push(`${ind(d + 1)}right:`); + lines.push(printReactiveValue(value.right, d + 2, outlinedCollector)); + lines.push(`${ind(d + 1)}loc: ${formatLoc(value.loc)}`); + lines.push(`${ind(d)}}`); + break; + case "ConditionalExpression": + lines.push(`${ind(d)}ConditionalExpression {`); + lines.push(`${ind(d + 1)}test:`); + lines.push(printReactiveValue(value.test, d + 2, outlinedCollector)); + lines.push(`${ind(d + 1)}consequent:`); + lines.push( + printReactiveValue(value.consequent, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}alternate:`); + lines.push( + printReactiveValue(value.alternate, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}loc: ${formatLoc(value.loc)}`); + lines.push(`${ind(d)}}`); + break; + case "SequenceExpression": + lines.push(`${ind(d)}SequenceExpression {`); + lines.push(`${ind(d + 1)}id: ${value.id}`); + lines.push(`${ind(d + 1)}instructions:`); + for (const instr of value.instructions) { + lines.push(printReactiveInstruction(instr, d + 2, outlinedCollector)); + } + lines.push(`${ind(d + 1)}value:`); + lines.push(printReactiveValue(value.value, d + 2, outlinedCollector)); + lines.push(`${ind(d + 1)}loc: ${formatLoc(value.loc)}`); + lines.push(`${ind(d)}}`); + break; + case "OptionalExpression": + lines.push(`${ind(d)}OptionalExpression {`); + lines.push(`${ind(d + 1)}id: ${value.id}`); + lines.push(`${ind(d + 1)}optional: ${value.optional}`); + lines.push(`${ind(d + 1)}value:`); + lines.push(printReactiveValue(value.value, d + 2, outlinedCollector)); + lines.push(`${ind(d + 1)}loc: ${formatLoc(value.loc)}`); + lines.push(`${ind(d)}}`); + break; + default: + // Plain InstructionValue + lines.push(printInstructionValueFields(value, d)); + break; + } + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Reactive instruction printing +// --------------------------------------------------------------------------- + +function printReactiveInstruction(instr, depth, outlinedCollector) { + const lines = []; + lines.push(`${ind(depth)}[${instr.id}] ReactiveInstruction {`); + const d = depth + 1; + lines.push(`${ind(d)}id: ${instr.id}`); + // lvalue + if (instr.lvalue != null) { + lines.push(`${ind(d)}lvalue:`); + lines.push(printPlaceInline(instr.lvalue, d + 1)); + } else { + lines.push(`${ind(d)}lvalue: null`); + } + // value + lines.push(`${ind(d)}value:`); + lines.push(printReactiveValue(instr.value, d + 1, outlinedCollector)); + // Collect outlined functions + collectOutlinedFromValue(instr.value, outlinedCollector); + // effects + if (instr.effects != null) { + lines.push(`${ind(d)}effects: [${instr.effects.length} effects]`); + } else { + lines.push(`${ind(d)}effects: null`); + } + lines.push(`${ind(d)}loc: ${formatLoc(instr.loc)}`); + lines.push(`${ind(depth)}}`); + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Reactive scope printing +// --------------------------------------------------------------------------- + +function printReactiveScopeDetails(scope, depth) { + const lines = []; + const d = depth; + lines.push(`${ind(d)}scope @${scope.id} {`); + lines.push(`${ind(d + 1)}id: ${scope.id}`); + lines.push( + `${ind(d + 1)}range: ${formatMutableRange(scope.range)}` + ); + // dependencies + const deps = [...scope.dependencies]; + lines.push(`${ind(d + 1)}dependencies: [${deps.length}]`); + for (const dep of deps) { + const path = dep.path + .map((p) => `${p.optional ? "?." : "."}${p.property}`) + .join(""); + lines.push( + `${ind(d + 2)}$${dep.identifier.id}${path} (reactive=${dep.reactive})` + ); + } + // declarations + const decls = [...scope.declarations].sort((a, b) => a[0] - b[0]); + lines.push(`${ind(d + 1)}declarations: [${decls.length}]`); + for (const [id, decl] of decls) { + lines.push(`${ind(d + 2)}$${id}: $${decl.identifier.id}`); + } + // reassignments + const reassigns = [...scope.reassignments]; + lines.push(`${ind(d + 1)}reassignments: [${reassigns.length}]`); + for (const ident of reassigns) { + lines.push(`${ind(d + 2)}$${ident.id}`); + } + // earlyReturnValue + if (scope.earlyReturnValue != null) { + lines.push(`${ind(d + 1)}earlyReturnValue:`); + lines.push( + `${ind(d + 2)}value: $${scope.earlyReturnValue.value.id}` + ); + lines.push( + `${ind(d + 2)}label: bb${scope.earlyReturnValue.label}` + ); + } else { + lines.push(`${ind(d + 1)}earlyReturnValue: null`); + } + // merged + const merged = [...scope.merged]; + if (merged.length > 0) { + lines.push( + `${ind(d + 1)}merged: [${merged.map((m) => `@${m}`).join(", ")}]` + ); + } else { + lines.push(`${ind(d + 1)}merged: []`); + } + lines.push(`${ind(d + 1)}loc: ${formatLoc(scope.loc)}`); + lines.push(`${ind(d)}}`); + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Reactive terminal printing +// --------------------------------------------------------------------------- + +function printReactiveTerminal(terminal, depth, outlinedCollector) { + const lines = []; + const d = depth; + const kind = terminal.kind; + + lines.push(`${ind(d)}${reactiveTerminalName(kind)} {`); + lines.push(`${ind(d + 1)}id: ${terminal.id}`); + + switch (kind) { + case "break": + lines.push(`${ind(d + 1)}target: bb${terminal.target}`); + lines.push(`${ind(d + 1)}targetKind: ${terminal.targetKind}`); + break; + case "continue": + lines.push(`${ind(d + 1)}target: bb${terminal.target}`); + lines.push(`${ind(d + 1)}targetKind: ${terminal.targetKind}`); + break; + case "return": + lines.push(`${ind(d + 1)}value:`); + lines.push(printPlaceInline(terminal.value, d + 2)); + break; + case "throw": + lines.push(`${ind(d + 1)}value:`); + lines.push(printPlaceInline(terminal.value, d + 2)); + break; + case "if": + lines.push(`${ind(d + 1)}test:`); + lines.push(printPlaceInline(terminal.test, d + 2)); + lines.push(`${ind(d + 1)}consequent:`); + lines.push( + printReactiveBlock(terminal.consequent, d + 2, outlinedCollector) + ); + if (terminal.alternate != null) { + lines.push(`${ind(d + 1)}alternate:`); + lines.push( + printReactiveBlock(terminal.alternate, d + 2, outlinedCollector) + ); + } else { + lines.push(`${ind(d + 1)}alternate: null`); + } + break; + case "switch": + lines.push(`${ind(d + 1)}test:`); + lines.push(printPlaceInline(terminal.test, d + 2)); + lines.push(`${ind(d + 1)}cases:`); + for (const c of terminal.cases) { + if (c.test != null) { + lines.push(`${ind(d + 2)}case $${c.test.identifier.id}:`); + } else { + lines.push(`${ind(d + 2)}default:`); + } + if (c.block != null) { + lines.push(printReactiveBlock(c.block, d + 3, outlinedCollector)); + } else { + lines.push(`${ind(d + 3)}(empty)`); + } + } + break; + case "do-while": + lines.push(`${ind(d + 1)}loop:`); + lines.push( + printReactiveBlock(terminal.loop, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}test:`); + lines.push( + printReactiveValue(terminal.test, d + 2, outlinedCollector) + ); + break; + case "while": + lines.push(`${ind(d + 1)}test:`); + lines.push( + printReactiveValue(terminal.test, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}loop:`); + lines.push( + printReactiveBlock(terminal.loop, d + 2, outlinedCollector) + ); + break; + case "for": + lines.push(`${ind(d + 1)}init:`); + lines.push( + printReactiveValue(terminal.init, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}test:`); + lines.push( + printReactiveValue(terminal.test, d + 2, outlinedCollector) + ); + if (terminal.update != null) { + lines.push(`${ind(d + 1)}update:`); + lines.push( + printReactiveValue(terminal.update, d + 2, outlinedCollector) + ); + } else { + lines.push(`${ind(d + 1)}update: null`); + } + lines.push(`${ind(d + 1)}loop:`); + lines.push( + printReactiveBlock(terminal.loop, d + 2, outlinedCollector) + ); + break; + case "for-of": + lines.push(`${ind(d + 1)}init:`); + lines.push( + printReactiveValue(terminal.init, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}test:`); + lines.push( + printReactiveValue(terminal.test, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}loop:`); + lines.push( + printReactiveBlock(terminal.loop, d + 2, outlinedCollector) + ); + break; + case "for-in": + lines.push(`${ind(d + 1)}init:`); + lines.push( + printReactiveValue(terminal.init, d + 2, outlinedCollector) + ); + lines.push(`${ind(d + 1)}loop:`); + lines.push( + printReactiveBlock(terminal.loop, d + 2, outlinedCollector) + ); + break; + case "label": + lines.push(`${ind(d + 1)}block:`); + lines.push( + printReactiveBlock(terminal.block, d + 2, outlinedCollector) + ); + break; + case "try": + lines.push(`${ind(d + 1)}block:`); + lines.push( + printReactiveBlock(terminal.block, d + 2, outlinedCollector) + ); + if (terminal.handlerBinding != null) { + lines.push(`${ind(d + 1)}handlerBinding:`); + lines.push(printPlaceInline(terminal.handlerBinding, d + 2)); + } else { + lines.push(`${ind(d + 1)}handlerBinding: null`); + } + lines.push(`${ind(d + 1)}handler:`); + lines.push( + printReactiveBlock(terminal.handler, d + 2, outlinedCollector) + ); + break; + default: + break; + } + + lines.push(`${ind(d + 1)}loc: ${formatLoc(terminal.loc)}`); + lines.push(`${ind(d)}}`); + return lines.join("\n"); +} + +function reactiveTerminalName(kind) { + const names = { + break: "Break", + continue: "Continue", + return: "Return", + throw: "Throw", + if: "If", + switch: "Switch", + "do-while": "DoWhile", + while: "While", + for: "For", + "for-of": "ForOf", + "for-in": "ForIn", + label: "Label", + try: "Try", + }; + return names[kind] ?? kind; +} + +// --------------------------------------------------------------------------- +// Reactive block printing (array of ReactiveStatements) +// --------------------------------------------------------------------------- + +function printReactiveBlock(block, depth, outlinedCollector) { + if (block == null || block.length === 0) { + return `${ind(depth)}(empty block)`; + } + const lines = []; + for (const stmt of block) { + lines.push(printReactiveStatement(stmt, depth, outlinedCollector)); + } + return lines.join("\n"); +} + +function printReactiveStatement(stmt, depth, outlinedCollector) { + const lines = []; + const d = depth; + + switch (stmt.kind) { + case "instruction": + lines.push( + printReactiveInstruction(stmt.instruction, d, outlinedCollector) + ); + break; + case "scope": + lines.push(`${ind(d)}ReactiveScopeBlock {`); + lines.push(printReactiveScopeDetails(stmt.scope, d + 1)); + lines.push(`${ind(d + 1)}instructions:`); + lines.push( + printReactiveBlock(stmt.instructions, d + 2, outlinedCollector) + ); + lines.push(`${ind(d)}}`); + break; + case "pruned-scope": + lines.push(`${ind(d)}PrunedReactiveScopeBlock {`); + lines.push(printReactiveScopeDetails(stmt.scope, d + 1)); + lines.push(`${ind(d + 1)}instructions:`); + lines.push( + printReactiveBlock(stmt.instructions, d + 2, outlinedCollector) + ); + lines.push(`${ind(d)}}`); + break; + case "terminal": + if (stmt.label != null) { + lines.push( + `${ind(d)}label bb${stmt.label.id} (implicit=${stmt.label.implicit}):` + ); + } + lines.push( + printReactiveTerminal(stmt.terminal, d, outlinedCollector) + ); + break; + default: + lines.push(`${ind(d)}Unknown statement kind: ${stmt.kind}`); + break; + } + + return lines.join("\n"); +} + +// --------------------------------------------------------------------------- +// Collect outlined functions from reactive values +// --------------------------------------------------------------------------- + +function collectOutlinedFromValue(value, collector) { + if (value == null) return; + if ( + value.kind === "FunctionExpression" || + value.kind === "ObjectMethod" + ) { + // The loweredFunc in reactive context points to an HIRFunction + // which in turn has a reactive body after BuildReactiveFunction. + // But outlined functions are collected from env, so we just track + // them for the main function printer. + } + // For reactive compound values, recurse + if (value.kind === "SequenceExpression") { + for (const instr of value.instructions) { + collectOutlinedFromValue(instr.value, collector); + } + collectOutlinedFromValue(value.value, collector); + } else if (value.kind === "LogicalExpression") { + collectOutlinedFromValue(value.left, collector); + collectOutlinedFromValue(value.right, collector); + } else if (value.kind === "ConditionalExpression") { + collectOutlinedFromValue(value.test, collector); + collectOutlinedFromValue(value.consequent, collector); + collectOutlinedFromValue(value.alternate, collector); + } else if (value.kind === "OptionalExpression") { + collectOutlinedFromValue(value.value, collector); + } +} + +// --------------------------------------------------------------------------- +// Main function printer +// --------------------------------------------------------------------------- + +function printReactiveFunction(fn, functionIndex, outlinedCollector) { + const lines = []; + const d0 = 0; + const d1 = 1; + const d2 = 2; + + lines.push(`${ind(d0)}ReactiveFunction #${functionIndex}:`); + + // id + lines.push( + `${ind(d1)}id: ${fn.id != null ? JSON.stringify(fn.id) : "null"}` + ); + + // nameHint + lines.push( + `${ind(d1)}nameHint: ${fn.nameHint != null ? JSON.stringify(fn.nameHint) : "null"}` + ); + + // params + lines.push(`${ind(d1)}params:`); + for (let i = 0; i < fn.params.length; i++) { + const param = fn.params[i]; + if (param.kind === "Identifier") { + lines.push(`${ind(d2)}[${i}]`); + lines.push(printPlaceInline(param, d2 + 1)); + } else { + lines.push(`${ind(d2)}[${i}] ...`); + lines.push(printPlaceInline(param.place, d2 + 1)); + } + } + + // generator / async + lines.push(`${ind(d1)}generator: ${fn.generator}`); + lines.push(`${ind(d1)}async: ${fn.async}`); + + // directives + if (fn.directives.length > 0) { + lines.push( + `${ind(d1)}directives: [${fn.directives.map((d) => JSON.stringify(d)).join(", ")}]` + ); + } else { + lines.push(`${ind(d1)}directives: []`); + } + + // loc + lines.push(`${ind(d1)}loc: ${formatLoc(fn.loc)}`); + + // body + lines.push(""); + lines.push(`${ind(d1)}body:`); + lines.push(printReactiveBlock(fn.body, d2, outlinedCollector)); + + // Outlined functions from env + if (fn.env != null && typeof fn.env.getOutlinedFunctions === "function") { + const outlinedFns = fn.env.getOutlinedFunctions(); + for (const outlined of outlinedFns) { + outlinedCollector.push(outlined.fn); + } + } + + return lines.join("\n"); +} diff --git a/compiler/scripts/enable-feature-flag.js b/compiler/scripts/enable-feature-flag.js new file mode 100755 index 000000000000..f51c5b484171 --- /dev/null +++ b/compiler/scripts/enable-feature-flag.js @@ -0,0 +1,347 @@ +#!/usr/bin/env node +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const {execSync} = require('child_process'); +const yargs = require('yargs/yargs'); +const {hideBin} = require('yargs/helpers'); + +// Constants +const COMPILER_ROOT = path.resolve(__dirname, '..'); +const ENVIRONMENT_TS_PATH = path.join( + COMPILER_ROOT, + 'packages/babel-plugin-react-compiler/src/HIR/Environment.ts' +); +const FIXTURES_PATH = path.join( + COMPILER_ROOT, + 'packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler' +); +const FIXTURE_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx']; + +/** + * Parse command line arguments + */ +function parseArgs() { + const argv = yargs(hideBin(process.argv)) + .usage('Usage: $0 ') + .command('$0 ', 'Enable a feature flag by default', yargs => { + yargs.positional('flag-name', { + describe: 'Name of the feature flag to enable', + type: 'string', + }); + }) + .example( + '$0 validateExhaustiveMemoizationDependencies', + 'Enable the validateExhaustiveMemoizationDependencies flag' + ) + .help('h') + .alias('h', 'help') + .strict() + .parseSync(); + + return argv['flag-name']; +} + +/** + * Enable a feature flag in Environment.ts by changing default(false) to default(true) + */ +function enableFlagInEnvironment(flagName) { + console.log(`\nEnabling flag "${flagName}" in Environment.ts...`); + + const content = fs.readFileSync(ENVIRONMENT_TS_PATH, 'utf8'); + + // Check if the flag exists with default(false) + const flagPatternFalse = new RegExp( + `(${escapeRegex(flagName)}:\\s*z\\.boolean\\(\\)\\.default\\()false(\\))`, + 'g' + ); + + if (!flagPatternFalse.test(content)) { + // Check if flag exists at all + const flagExistsPattern = new RegExp( + `${escapeRegex(flagName)}:\\s*z\\.boolean\\(\\)`, + 'g' + ); + if (flagExistsPattern.test(content)) { + // Check if it's already true + const flagPatternTrue = new RegExp( + `${escapeRegex(flagName)}:\\s*z\\.boolean\\(\\)\\.default\\(true\\)`, + 'g' + ); + if (flagPatternTrue.test(content)) { + console.error(`Error: Flag "${flagName}" already has default(true)`); + process.exit(1); + } + console.error( + `Error: Flag "${flagName}" exists but doesn't have default(false)` + ); + process.exit(1); + } + console.error(`Error: Flag "${flagName}" not found in Environment.ts`); + process.exit(1); + } + + // Perform the replacement + const newContent = content.replace(flagPatternFalse, '$1true$2'); + + // Verify the replacement worked + if (content === newContent) { + console.error(`Error: Failed to replace flag "${flagName}"`); + process.exit(1); + } + + fs.writeFileSync(ENVIRONMENT_TS_PATH, newContent, 'utf8'); + console.log(`Successfully enabled "${flagName}" in Environment.ts`); +} + +/** + * Helper to escape regex special characters + */ +function escapeRegex(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +/** + * Run yarn snap and capture output + */ +function runTests() { + console.log('\nRunning test suite (yarn snap)...'); + + try { + const output = execSync('yarn snap', { + cwd: COMPILER_ROOT, + encoding: 'utf8', + stdio: 'pipe', + maxBuffer: 10 * 1024 * 1024, // 10MB buffer + }); + return {success: true, output}; + } catch (error) { + // yarn snap exits with code 1 when tests fail, which throws an error + return {success: false, output: error.stdout || error.message}; + } +} + +/** + * Parse failing test names from test output + */ +function parseFailingTests(output) { + const failingTests = []; + + // Look for lines that contain "FAIL:" followed by the test name + // Format: "FAIL: test-name" or with ANSI codes + const lines = output.split('\n'); + for (const line of lines) { + // Remove ANSI codes for easier parsing + const cleanLine = line.replace(/\x1b\[[0-9;]*m/g, ''); + + // Match "FAIL: test-name" + const match = cleanLine.match(/^FAIL:\s*(.+)$/); + if (match) { + failingTests.push(match[1].trim()); + } + } + + return failingTests; +} + +/** + * Find the fixture file for a given test name + */ +function findFixtureFile(testName) { + const basePath = path.join(FIXTURES_PATH, testName); + + for (const ext of FIXTURE_EXTENSIONS) { + const filePath = basePath + ext; + if (fs.existsSync(filePath)) { + return filePath; + } + } + + return null; +} + +/** + * Add pragma to disable the feature flag in a fixture file + */ +function addPragmaToFixture(filePath, flagName) { + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n'); + + if (lines.length === 0) { + console.warn(`Warning: Empty file ${filePath}`); + return false; + } + + const firstLine = lines[0]; + const pragma = `@${flagName}:false`; + + // Check if pragma already exists + if (firstLine.includes(pragma)) { + return false; // Already has the pragma + } + + // Check if first line is a single-line comment + if (firstLine.trim().startsWith('//')) { + // Append pragma to existing comment + lines[0] = firstLine + ' ' + pragma; + } else if (firstLine.trim().startsWith('/*')) { + // Multi-line comment - insert new line before it + lines.unshift('// ' + pragma); + } else { + // No comment - insert new comment as first line + lines.unshift('// ' + pragma); + } + + fs.writeFileSync(filePath, lines.join('\n'), 'utf8'); + return true; +} + +/** + * Update snapshot files + */ +function updateSnapshots() { + console.log('\nUpdating snapshots (yarn snap -u)...'); + + try { + execSync('yarn snap -u', { + cwd: COMPILER_ROOT, + encoding: 'utf8', + stdio: 'pipe', + maxBuffer: 10 * 1024 * 1024, + }); + console.log('Snapshots updated successfully'); + return true; + } catch (error) { + console.error('Error updating snapshots:', error.message); + return false; + } +} + +/** + * Verify all tests pass + */ +function verifyAllTestsPass() { + console.log('\nRunning final verification (yarn snap)...'); + + const {success, output} = runTests(); + + // Parse summary line: "N Tests, N Passed, N Failed" + const summaryMatch = output.match( + /(\d+)\s+Tests,\s+(\d+)\s+Passed,\s+(\d+)\s+Failed/ + ); + + if (summaryMatch) { + const [, total, passed, failed] = summaryMatch; + console.log( + `\nTest Results: ${total} Tests, ${passed} Passed, ${failed} Failed` + ); + + if (failed === '0') { + console.log('All tests passed!'); + return true; + } else { + console.error(`${failed} tests still failing`); + const failingTests = parseFailingTests(output); + if (failingTests.length > 0) { + console.error('\nFailing tests:'); + failingTests.forEach(test => console.error(` - ${test}`)); + } + return false; + } + } + + return success; +} + +/** + * Main function + */ +async function main() { + const flagName = parseArgs(); + + console.log(`\nEnabling flag: '${flagName}'`); + + try { + // Step 1: Enable flag in Environment.ts + enableFlagInEnvironment(flagName); + + // Step 2: Run tests to find failures + const {output} = runTests(); + const failingTests = parseFailingTests(output); + + console.log(`\nFound ${failingTests.length} failing tests`); + + if (failingTests.length === 0) { + console.log('No failing tests! Feature flag enabled successfully.'); + process.exit(0); + } + + // Step 3: Add pragma to each failing fixture + console.log(`\nAdding '@${flagName}:false' pragma to failing fixtures...`); + + const notFound = []; + let notFoundCount = 0; + + for (const testName of failingTests) { + const fixturePath = findFixtureFile(testName); + + if (!fixturePath) { + console.warn(`Could not find fixture file for: ${testName}`); + notFound.push(fixturePath); + continue; + } + + const updated = addPragmaToFixture(fixturePath, flagName); + if (updated) { + updatedCount++; + console.log(` Updated: ${testName}`); + } + } + + console.log( + `\nSummary: Updated ${updatedCount} fixtures, ${notFoundCount} not found` + ); + + if (notFoundCount.length !== 0) { + console.error( + '\nFailed to update snapshots, could not find:\n' + notFound.join('\n') + ); + process.exit(1); + } + + // Step 4: Update snapshots + if (!updateSnapshots()) { + console.error('\nFailed to update snapshots'); + process.exit(1); + } + + // Step 5: Verify all tests pass + if (!verifyAllTestsPass()) { + console.error('\nVerification failed: Some tests are still failing'); + process.exit(1); + } + + console.log('\nSuccess! Feature flag enabled and all tests passing.'); + console.log(`\nSummary:`); + console.log(` - Enabled "${flagName}" in Environment.ts`); + console.log(` - Updated ${updatedCount} fixture files with pragma`); + console.log(` - All tests passing`); + + process.exit(0); + } catch (error) { + console.error('\nFatal error:', error.message); + console.error(error.stack); + process.exit(1); + } +} + +// Run the script +main(); diff --git a/compiler/scripts/hash.sh b/compiler/scripts/hash.sh new file mode 100755 index 000000000000..2d454af67dbd --- /dev/null +++ b/compiler/scripts/hash.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +set -eo pipefail + +# Hashes JS files in the provided directory to create a cache-breaker + +find $1 -name '*.js' | sort | xargs shasum | shasum | awk '{ print $1 }' diff --git a/compiler/scripts/profile-rust-port.sh b/compiler/scripts/profile-rust-port.sh new file mode 100755 index 000000000000..089c029dc0d7 --- /dev/null +++ b/compiler/scripts/profile-rust-port.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Thin wrapper for the profiling script. +# +# Usage: bash compiler/scripts/profile-rust-port.sh [flags] +# Flags: --release, --json, --limit N + +set -eo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +exec npx tsx "$REPO_ROOT/compiler/scripts/profile-rust-port.ts" "$@" diff --git a/compiler/scripts/profile-rust-port.ts b/compiler/scripts/profile-rust-port.ts new file mode 100644 index 000000000000..7206a7dd6533 --- /dev/null +++ b/compiler/scripts/profile-rust-port.ts @@ -0,0 +1,640 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Performance profiling script for Rust vs JS React Compiler. + * + * Runs both compilers on all fixtures without debug logging, + * collects fine-grained timing data at every stage, and reports + * aggregate performance breakdowns. + * + * Usage: npx tsx compiler/scripts/profile-rust-port.ts [flags] + * + * Flags: + * --release Build and use release-mode Rust binary + * --json Output JSON instead of formatted tables + * --limit N Max fixtures to profile (default: all) + */ + +import * as babel from '@babel/core'; +import {execSync} from 'child_process'; +import fs from 'fs'; +import path from 'path'; + +import {parseConfigPragmaForTests} from '../packages/babel-plugin-react-compiler/src/Utils/TestUtils'; + +const REPO_ROOT = path.resolve(__dirname, '../..'); + +// --- Parse flags --- +const rawArgs = process.argv.slice(2); +const releaseMode = rawArgs.includes('--release'); +const jsonMode = rawArgs.includes('--json'); +const limitIdx = rawArgs.indexOf('--limit'); +const limitArg = limitIdx >= 0 ? parseInt(rawArgs[limitIdx + 1], 10) : 0; + +// --- ANSI colors --- +const useColor = !jsonMode; +const BOLD = useColor ? '\x1b[1m' : ''; +const DIM = useColor ? '\x1b[2m' : ''; +const RED = useColor ? '\x1b[0;31m' : ''; +const GREEN = useColor ? '\x1b[0;32m' : ''; +const YELLOW = useColor ? '\x1b[0;33m' : ''; +const CYAN = useColor ? '\x1b[0;36m' : ''; +const RESET = useColor ? '\x1b[0m' : ''; + +// --- Build native module --- +const NATIVE_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler-rust/native', +); +const NATIVE_NODE_PATH = path.join(NATIVE_DIR, 'index.node'); + +if (!jsonMode) { + console.log( + `Building Rust native module (${releaseMode ? 'release' : 'debug'})...`, + ); +} + +// Profiling needs symbol names; override the release profile's strip=true. +const cargoBuildArgs = releaseMode + ? "--release --config 'profile.release.strip=false' -p react_compiler_napi" + : '-p react_compiler_napi'; + +try { + execSync(`~/.cargo/bin/cargo build ${cargoBuildArgs}`, { + cwd: path.join(REPO_ROOT, 'compiler/crates'), + stdio: jsonMode ? ['inherit', 'pipe', 'inherit'] : 'inherit', + shell: true, + }); +} catch { + console.error('ERROR: Failed to build Rust native module.'); + process.exit(1); +} + +// Copy the built dylib as index.node +const TARGET_DIR = path.join( + REPO_ROOT, + releaseMode ? 'compiler/target/release' : 'compiler/target/debug', +); +const dylib = fs.existsSync( + path.join(TARGET_DIR, 'libreact_compiler_napi.dylib'), +) + ? path.join(TARGET_DIR, 'libreact_compiler_napi.dylib') + : path.join(TARGET_DIR, 'libreact_compiler_napi.so'); + +if (!fs.existsSync(dylib)) { + console.error(`ERROR: Could not find built native module in ${TARGET_DIR}`); + process.exit(1); +} +fs.copyFileSync(dylib, NATIVE_NODE_PATH); + +// --- Load plugins --- +const tsPlugin = require('../packages/babel-plugin-react-compiler/src').default; +const {extractScopeInfo} = + require('../packages/babel-plugin-react-compiler-rust/src/scope') as typeof import('../packages/babel-plugin-react-compiler-rust/src/scope'); +const {resolveOptions} = + require('../packages/babel-plugin-react-compiler-rust/src/options') as typeof import('../packages/babel-plugin-react-compiler-rust/src/options'); +const {compileWithRustProfiled} = + require('../packages/babel-plugin-react-compiler-rust/src/bridge') as typeof import('../packages/babel-plugin-react-compiler-rust/src/bridge'); + +// --- Types --- +interface TimingEntry { + name: string; + duration_us: number; +} + +interface BridgeTiming { + jsStringifyAst_us: number; + jsStringifyScope_us: number; + jsStringifyOptions_us: number; + napiCall_us: number; + jsParseResult_us: number; +} + +interface FixtureProfile { + fixture: string; + sizeBytes: number; + tsTotal_us: number; + rustTotal_us: number; + rustScopeExtraction_us: number; + rustBridge: BridgeTiming; + rustPasses: TimingEntry[]; +} + +// --- Discover fixtures --- +function discoverFixtures(rootPath: string): string[] { + const results: string[] = []; + function walk(dir: string): void { + for (const entry of fs.readdirSync(dir, {withFileTypes: true})) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walk(fullPath); + } else if ( + /\.(js|jsx|ts|tsx)$/.test(entry.name) && + !entry.name.endsWith('.expect.md') + ) { + results.push(fullPath); + } + } + } + walk(rootPath); + results.sort(); + return results; +} + +// --- Compile fixture with TS compiler (no debug logging) --- +function compileWithTS(fixturePath: string): number { + const source = fs.readFileSync(fixturePath, 'utf8'); + const firstLine = source.substring(0, source.indexOf('\n')); + const pragmaOpts = parseConfigPragmaForTests(firstLine, { + compilationMode: 'all', + }); + + const isFlow = firstLine.includes('@flow'); + const isScript = firstLine.includes('@script'); + const parserPlugins: string[] = isFlow + ? ['flow', 'jsx'] + : ['typescript', 'jsx']; + + const start = performance.now(); + try { + babel.transformSync(source, { + filename: fixturePath, + sourceType: isScript ? 'script' : 'module', + parserOpts: {plugins: parserPlugins}, + plugins: [ + [ + tsPlugin, + { + ...pragmaOpts, + compilationMode: 'all' as const, + panicThreshold: 'all_errors' as const, + }, + ], + ], + configFile: false, + babelrc: false, + }); + } catch { + // Ignore errors - we still measure timing + } + const end = performance.now(); + return Math.round((end - start) * 1000); // microseconds +} + +// --- Compile fixture with Rust compiler (profiled) --- +function compileWithRustProfile(fixturePath: string): { + total_us: number; + scopeExtraction_us: number; + bridge: BridgeTiming; + passes: TimingEntry[]; +} { + const source = fs.readFileSync(fixturePath, 'utf8'); + const firstLine = source.substring(0, source.indexOf('\n')); + const pragmaOpts = parseConfigPragmaForTests(firstLine, { + compilationMode: 'all', + }); + + const isFlow = firstLine.includes('@flow'); + const isScript = firstLine.includes('@script'); + const parserPlugins: string[] = isFlow + ? ['flow', 'jsx'] + : ['typescript', 'jsx']; + + // Parse the AST via Babel (same as the real plugin) + const parseResult = babel.transformSync(source, { + filename: fixturePath, + sourceType: isScript ? 'script' : 'module', + parserOpts: {plugins: parserPlugins}, + plugins: [ + // Use a minimal plugin that captures the AST and scope info + function capturePlugin(_api: typeof babel): babel.PluginObj { + return { + name: 'capture', + visitor: { + Program: { + enter(prog, pass): void { + // Resolve options + const opts = resolveOptions( + { + ...pragmaOpts, + compilationMode: 'all', + panicThreshold: 'all_errors', + }, + pass.file, + fixturePath, + pass.file.ast, + ); + + // Extract scope info (timed) + const scopeStart = performance.now(); + let scopeInfo; + try { + scopeInfo = extractScopeInfo(prog); + } catch { + // Store failed result + (pass as any).__profileResult = { + total_us: Math.round( + (performance.now() - scopeStart) * 1000, + ), + scopeExtraction_us: Math.round( + (performance.now() - scopeStart) * 1000, + ), + bridge: { + jsStringifyAst_us: 0, + jsStringifyScope_us: 0, + jsStringifyOptions_us: 0, + napiCall_us: 0, + jsParseResult_us: 0, + }, + passes: [], + }; + return; + } + const scopeEnd = performance.now(); + + const totalStart = performance.now(); + try { + const profiled = compileWithRustProfiled( + pass.file.ast, + scopeInfo, + opts, + pass.file.code ?? null, + ); + const totalEnd = performance.now(); + + (pass as any).__profileResult = { + total_us: Math.round((totalEnd - totalStart) * 1000), + scopeExtraction_us: Math.round( + (scopeEnd - scopeStart) * 1000, + ), + bridge: profiled.bridgeTiming, + passes: profiled.rustTiming, + }; + } catch { + const totalEnd = performance.now(); + (pass as any).__profileResult = { + total_us: Math.round((totalEnd - totalStart) * 1000), + scopeExtraction_us: Math.round( + (scopeEnd - scopeStart) * 1000, + ), + bridge: { + jsStringifyAst_us: 0, + jsStringifyScope_us: 0, + jsStringifyOptions_us: 0, + napiCall_us: 0, + jsParseResult_us: 0, + }, + passes: [], + }; + } + prog.skip(); + }, + }, + }, + }; + }, + ], + configFile: false, + babelrc: false, + }); + + // Extract the profile result stored by the plugin + const result = (parseResult as any)?.metadata?.__profileResult ?? + (parseResult as any)?.__profileResult ?? { + total_us: 0, + scopeExtraction_us: 0, + bridge: { + jsStringifyAst_us: 0, + jsStringifyScope_us: 0, + jsStringifyOptions_us: 0, + napiCall_us: 0, + jsParseResult_us: 0, + }, + passes: [], + }; + + return result; +} + +// --- Compile fixture with Rust compiler (simpler approach using direct API) --- +function compileWithRustDirect(fixturePath: string): { + total_us: number; + scopeExtraction_us: number; + bridge: BridgeTiming; + passes: TimingEntry[]; +} { + const source = fs.readFileSync(fixturePath, 'utf8'); + const firstLine = source.substring(0, source.indexOf('\n')); + const pragmaOpts = parseConfigPragmaForTests(firstLine, { + compilationMode: 'all', + }); + + const isFlow = firstLine.includes('@flow'); + const isScript = firstLine.includes('@script'); + const parserPlugins: string[] = isFlow + ? ['flow', 'jsx'] + : ['typescript', 'jsx']; + + // Parse the AST via Babel + let ast: babel.types.File | null = null; + let scopeInfo: any = null; + let opts: any = null; + let scopeExtraction_us = 0; + + try { + babel.transformSync(source, { + filename: fixturePath, + sourceType: isScript ? 'script' : 'module', + parserOpts: {plugins: parserPlugins}, + plugins: [ + function capturePlugin(_api: typeof babel): babel.PluginObj { + return { + name: 'capture-for-profile', + visitor: { + Program: { + enter(prog, pass): void { + ast = pass.file.ast; + opts = resolveOptions( + { + ...pragmaOpts, + compilationMode: 'all', + panicThreshold: 'all_errors', + }, + pass.file, + fixturePath, + pass.file.ast, + ); + + const scopeStart = performance.now(); + try { + scopeInfo = extractScopeInfo(prog); + } catch { + scopeInfo = null; + } + scopeExtraction_us = Math.round( + (performance.now() - scopeStart) * 1000, + ); + prog.skip(); + }, + }, + }, + }; + }, + ], + configFile: false, + babelrc: false, + }); + } catch { + // Parse error or other babel failure - skip this fixture + } + + if (ast == null || scopeInfo == null || opts == null) { + return { + total_us: 0, + scopeExtraction_us, + bridge: { + jsStringifyAst_us: 0, + jsStringifyScope_us: 0, + jsStringifyOptions_us: 0, + napiCall_us: 0, + jsParseResult_us: 0, + }, + passes: [], + }; + } + + const totalStart = performance.now(); + try { + const profiled = compileWithRustProfiled(ast, scopeInfo, opts, source); + const totalEnd = performance.now(); + + return { + total_us: Math.round((totalEnd - totalStart) * 1000), + scopeExtraction_us, + bridge: profiled.bridgeTiming, + passes: profiled.rustTiming, + }; + } catch { + const totalEnd = performance.now(); + return { + total_us: Math.round((totalEnd - totalStart) * 1000), + scopeExtraction_us, + bridge: { + jsStringifyAst_us: 0, + jsStringifyScope_us: 0, + jsStringifyOptions_us: 0, + napiCall_us: 0, + jsParseResult_us: 0, + }, + passes: [], + }; + } +} + +// --- Main --- +const DEFAULT_FIXTURES_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler', +); + +let fixtures = discoverFixtures(DEFAULT_FIXTURES_DIR); +if (limitArg > 0) { + fixtures = fixtures.slice(0, limitArg); +} + +if (fixtures.length === 0) { + console.error('No fixtures found.'); + process.exit(1); +} + +if (!jsonMode) { + console.log(`\nProfiling ${BOLD}${fixtures.length}${RESET} fixtures...`); +} + +// --- Warmup pass --- +if (!jsonMode) { + console.log(`${DIM}Warmup pass (results discarded)...${RESET}`); +} +for (const fixturePath of fixtures) { + compileWithTS(fixturePath); + compileWithRustDirect(fixturePath); +} + +// --- Profile pass --- +if (!jsonMode) { + console.log(`Profiling...`); +} + +const profiles: FixtureProfile[] = []; + +for (const fixturePath of fixtures) { + const relPath = path.relative(REPO_ROOT, fixturePath); + const sizeBytes = fs.statSync(fixturePath).size; + + const tsTotal_us = compileWithTS(fixturePath); + const rustResult = compileWithRustDirect(fixturePath); + + profiles.push({ + fixture: relPath, + sizeBytes, + tsTotal_us, + rustTotal_us: rustResult.scopeExtraction_us + rustResult.total_us, + rustScopeExtraction_us: rustResult.scopeExtraction_us, + rustBridge: rustResult.bridge, + rustPasses: rustResult.passes, + }); +} + +// --- Aggregation --- +const totalTS = profiles.reduce((sum, p) => sum + p.tsTotal_us, 0); +const totalRust = profiles.reduce((sum, p) => sum + p.rustTotal_us, 0); +const ratio = totalRust / totalTS; + +// Aggregate pass timing +const passAggregates = new Map(); + +function addPassTiming(name: string, duration_us: number): void { + let agg = passAggregates.get(name); + if (!agg) { + agg = {total_us: 0, values: []}; + passAggregates.set(name, agg); + } + agg.total_us += duration_us; + agg.values.push(duration_us); +} + +for (const profile of profiles) { + // Bridge phases + addPassTiming('JS: extractScopeInfo', profile.rustScopeExtraction_us); + addPassTiming('JS: JSON.stringify AST', profile.rustBridge.jsStringifyAst_us); + addPassTiming( + 'JS: JSON.stringify scope', + profile.rustBridge.jsStringifyScope_us, + ); + addPassTiming( + 'JS: JSON.stringify options', + profile.rustBridge.jsStringifyOptions_us, + ); + addPassTiming('JS: JSON.parse result', profile.rustBridge.jsParseResult_us); + + // Rust passes + for (const pass of profile.rustPasses) { + addPassTiming(`Rust: ${pass.name}`, pass.duration_us); + } +} + +function percentile(values: number[], p: number): number { + const sorted = [...values].sort((a, b) => a - b); + const idx = Math.ceil((p / 100) * sorted.length) - 1; + return sorted[Math.max(0, idx)]; +} + +// --- Output --- +if (jsonMode) { + const output = { + build: releaseMode ? 'release' : 'debug', + fixtureCount: fixtures.length, + totalTS_us: totalTS, + totalRust_us: totalRust, + ratio: Math.round(ratio * 100) / 100, + passAggregates: Object.fromEntries( + [...passAggregates.entries()].map(([name, agg]) => [ + name, + { + total_us: agg.total_us, + avg_us: Math.round(agg.total_us / agg.values.length), + p95_us: percentile(agg.values, 95), + count: agg.values.length, + }, + ]), + ), + fixtures: profiles, + }; + console.log(JSON.stringify(output, null, 2)); +} else { + console.log(''); + console.log(`${BOLD}=== Summary ===${RESET}`); + console.log( + `Build: ${CYAN}${releaseMode ? 'release' : 'debug'}${RESET} | Fixtures: ${BOLD}${fixtures.length}${RESET} | Warmup: done`, + ); + console.log(''); + + const tsMs = (totalTS / 1000).toFixed(1); + const rustMs = (totalRust / 1000).toFixed(1); + const ratioStr = ratio.toFixed(2); + const ratioColor = ratio <= 1.0 ? GREEN : ratio <= 1.5 ? YELLOW : RED; + console.log( + `Total: TS ${BOLD}${tsMs}ms${RESET} | Rust ${BOLD}${rustMs}ms${RESET} | Ratio ${ratioColor}${ratioStr}x${RESET}`, + ); + console.log(''); + + // --- Pass breakdown table --- + console.log(`${BOLD}=== Rust Time Breakdown (aggregate) ===${RESET}`); + + // Sort by total time descending + const sortedPasses = [...passAggregates.entries()].sort( + (a, b) => b[1].total_us - a[1].total_us, + ); + + const header = `${'Phase'.padEnd(50)} ${'Total(ms)'.padStart(10)} ${'%'.padStart(6)} ${'Avg(us)'.padStart(9)} ${'P95(us)'.padStart(9)}`; + console.log(`${DIM}${header}${RESET}`); + + for (const [name, agg] of sortedPasses) { + const totalMs = (agg.total_us / 1000).toFixed(1); + const pct = ((agg.total_us / totalRust) * 100).toFixed(1); + const avg = Math.round(agg.total_us / agg.values.length); + const p95 = percentile(agg.values, 95); + + console.log( + `${name.padEnd(50)} ${totalMs.padStart(10)} ${(pct + '%').padStart(6)} ${String(avg).padStart(9)} ${String(p95).padStart(9)}`, + ); + } + console.log(''); + + // --- Top 20 slowest fixtures --- + console.log(`${BOLD}=== Top 20 Slowest Fixtures (Rust) ===${RESET}`); + const sortedFixtures = [...profiles].sort( + (a, b) => b.rustTotal_us - a.rustTotal_us, + ); + const topN = sortedFixtures.slice(0, 20); + + const fHeader = `${'Fixture'.padEnd(55)} ${'Size'.padStart(6)} ${'TS(ms)'.padStart(8)} ${'Rust(ms)'.padStart(9)} ${'Ratio'.padStart(7)} ${'Bottleneck'.padStart(20)}`; + console.log(`${DIM}${fHeader}${RESET}`); + + for (const p of topN) { + const shortName = + p.fixture.length > 54 ? '...' + p.fixture.slice(-51) : p.fixture; + const sizeStr = + p.sizeBytes > 1024 + ? (p.sizeBytes / 1024).toFixed(0) + 'K' + : String(p.sizeBytes); + const tsMsStr = (p.tsTotal_us / 1000).toFixed(2); + const rustMsStr = (p.rustTotal_us / 1000).toFixed(2); + const fixtureRatio = p.tsTotal_us > 0 ? p.rustTotal_us / p.tsTotal_us : 0; + const ratioStr = fixtureRatio.toFixed(1) + 'x'; + const ratioColor = + fixtureRatio <= 1.0 ? GREEN : fixtureRatio <= 1.5 ? YELLOW : RED; + + // Find bottleneck pass + let bottleneck = ''; + if (p.rustPasses.length > 0) { + const sorted = [...p.rustPasses].sort( + (a, b) => b.duration_us - a.duration_us, + ); + const top = sorted[0]; + const pct = ((top.duration_us / p.rustTotal_us) * 100).toFixed(0); + bottleneck = `${top.name} (${pct}%)`; + } + const bottleneckStr = + bottleneck.length > 19 ? bottleneck.slice(0, 19) + 'โ€ฆ' : bottleneck; + + console.log( + `${shortName.padEnd(55)} ${sizeStr.padStart(6)} ${tsMsStr.padStart(8)} ${rustMsStr.padStart(9)} ${ratioColor}${ratioStr.padStart(7)}${RESET} ${bottleneckStr.padStart(20)}`, + ); + } +} diff --git a/compiler/scripts/release/ci-npmrc b/compiler/scripts/release/ci-npmrc new file mode 100644 index 000000000000..ae643592e765 --- /dev/null +++ b/compiler/scripts/release/ci-npmrc @@ -0,0 +1 @@ +//registry.npmjs.org/:_authToken=${NPM_TOKEN} diff --git a/compiler/scripts/release/prompt-for-otp.js b/compiler/scripts/release/prompt-for-otp.js new file mode 100644 index 000000000000..3cb1e419c784 --- /dev/null +++ b/compiler/scripts/release/prompt-for-otp.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const prompt = require('prompt-promise'); + +const run = async () => { + while (true) { + const otp = await prompt('NPM 2-factor auth code: '); + prompt.done(); + if (otp) { + return otp; + } else { + console.error('\nTwo-factor auth is required to publish.'); + // (Ask again.) + } + } +}; + +module.exports = run; diff --git a/compiler/scripts/release/publish.js b/compiler/scripts/release/publish.js new file mode 100755 index 000000000000..4ff332d300a3 --- /dev/null +++ b/compiler/scripts/release/publish.js @@ -0,0 +1,237 @@ +#!/usr/bin/env node +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const ora = require('ora'); +const path = require('path'); +const yargs = require('yargs'); +const {hashElement} = require('folder-hash'); +const promptForOTP = require('./prompt-for-otp'); +const {PUBLISHABLE_PACKAGES} = require('./shared/packages'); +const { + execHelper, + getDateStringForCommit, + spawnHelper, +} = require('./shared/utils'); +const {buildPackages} = require('./shared/build-packages'); +const {readJson, writeJson} = require('fs-extra'); + +/** + * Script for publishing PUBLISHABLE_PACKAGES to npm. By default, this runs in tarball mode, meaning + * the script will only print out what the contents of the files included in the npm tarball would + * be. + * + * Please run this first (ie `yarn npm:publish`) and double check the contents of the files that + * will be pushed to npm. + * + * If it looks good, you can run `yarn npm:publish --for-real` to really publish to npm. You must + * have 2FA enabled first and the script will prompt you to enter a 2FA code before proceeding. + * There's a small annoying delay before the packages are actually pushed to give you time to panic + * cancel. In this mode, we will bump the version field of each package's package.json, and git + * commit it. Then, the packages will be published to npm. + * + * Optionally, you can add the `--debug` flag to `yarn npm:publish --debug --for-real` to run all + * steps, but the final npm publish step will have the `--dry-run` flag added to it. This will make + * the command only report what it would have done, instead of actually publishing to npm. + */ +async function main() { + const argv = yargs(process.argv.slice(2)) + .option('packages', { + description: 'which packages to publish, defaults to all', + choices: PUBLISHABLE_PACKAGES, + default: PUBLISHABLE_PACKAGES, + }) + .option('for-real', { + alias: 'frfr', + description: + 'whether to publish to npm (npm publish) or dryrun (npm publish --dry-run)', + type: 'boolean', + default: false, + }) + .option('debug', { + description: + 'If enabled, will always run npm commands in dry run mode irregardless of the for-real flag', + type: 'boolean', + default: false, + }) + .option('ci', { + description: 'Publish packages via CI', + type: 'boolean', + default: false, + }) + .option('tag', { + description: 'Tag to publish to npm', + type: 'choices', + choices: ['experimental', 'beta', 'rc', 'latest'], + default: 'experimental', + }) + .option('tag-version', { + description: + 'Optional tag version to append to tag name, eg `1` becomes 0.0.0-rc.1', + type: 'number', + default: null, + }) + .option('version-name', { + description: 'Version name', + type: 'string', + default: '0.0.0', + }) + .help('help') + .strict() + .parseSync(); + + if (argv.debug === false) { + const currBranchName = await execHelper('git rev-parse --abbrev-ref HEAD'); + const isPristine = (await execHelper('git status --porcelain')) === ''; + if (currBranchName !== 'main' || isPristine === false) { + throw new Error( + 'This script must be run from the `main` branch with no uncommitted changes' + ); + } + } + + let pkgNames = argv.packages; + if (Array.isArray(argv.packages) === false) { + pkgNames = [argv.packages]; + } + const spinner = ora( + `Preparing to publish ${argv.versionName}@${argv.tag} ${ + argv.forReal === true ? '(for real)' : '(dry run)' + } [debug=${argv.debug}]` + ).info(); + + await buildPackages(pkgNames); + + if (argv.forReal === false) { + spinner.info('Dry run: Report tarball contents'); + for (const pkgName of pkgNames) { + console.log(`\n========== ${pkgName} ==========\n`); + spinner.start(`Running npm pack --dry-run\n`); + try { + await spawnHelper('npm', ['pack', '--dry-run'], { + cwd: path.resolve(__dirname, `../../packages/${pkgName}`), + stdio: 'inherit', + }); + } catch (e) { + spinner.fail(e.toString()); + throw e; + } + spinner.stop(`Successfully packed ${pkgName} (dry run)`); + } + spinner.succeed( + 'Please confirm contents of packages before publishing. You can run this command again with --for-real to publish to npm' + ); + } + + if (argv.forReal === true) { + const commit = await execHelper( + 'git show -s --no-show-signature --format=%h', + { + cwd: path.resolve(__dirname, '..'), + } + ); + const dateString = await getDateStringForCommit(commit); + const otp = + argv.ci === false && argv.debug === false ? await promptForOTP() : null; + const {hash} = await hashElement(path.resolve(__dirname, '../..'), { + encoding: 'hex', + folders: {exclude: ['node_modules']}, + files: {exclude: ['.DS_Store']}, + }); + const truncatedHash = hash.slice(0, 7); + let newVersion; + if (argv.tag === 'latest') { + newVersion = argv.versionName; + } else { + newVersion = + argv.tagVersion == null || argv.tagVersion === '' + ? `${argv.versionName}-${argv.tag}` + : `${argv.versionName}-${argv.tag}.${argv.tagVersion}`; + } + if (argv.tag === 'experimental' || argv.tag === 'beta') { + newVersion = `${newVersion}-${truncatedHash}-${dateString}`; + } + + for (const pkgName of pkgNames) { + const pkgDir = path.resolve(__dirname, `../../packages/${pkgName}`); + const pkgJsonPath = path.resolve( + __dirname, + `../../packages/${pkgName}/package.json` + ); + + spinner.start(`Writing package.json for ${pkgName}@${newVersion}`); + await writeJson( + pkgJsonPath, + { + ...(await readJson(pkgJsonPath)), + version: newVersion, + }, + {spaces: 2} + ); + spinner.succeed(`Wrote package.json for ${pkgName}@${newVersion}`); + + console.log(`\n========== ${pkgName} ==========\n`); + spinner.start(`Publishing ${pkgName}@${newVersion} to npm\n`); + + let opts = []; + if (argv.debug === true) { + opts.push('--dry-run'); + } + if (otp != null) { + opts.push(`--otp=${otp}`); + } + + opts.push(`--tag=${argv.tag}`); + + try { + await spawnHelper( + 'npm', + ['publish', ...opts, '--registry=https://registry.npmjs.org'], + { + cwd: pkgDir, + stdio: 'inherit', + } + ); + console.log('\n'); + } catch (e) { + spinner.fail(e.toString()); + throw e; + } + spinner.succeed(`Successfully published ${pkgName} to npm`); + + spinner.start('Pushing tags to npm'); + if (typeof argv.tag === 'string') { + try { + let opts = ['dist-tag', 'add', `${pkgName}@${newVersion}`, argv.tag]; + if (otp != null) { + opts.push(`--otp=${otp}`); + } + if (argv.debug === true) { + spinner.info(`dry-run: npm ${opts.join(' ')}`); + } else { + await spawnHelper('npm', opts, { + cwd: pkgDir, + stdio: 'inherit', + }); + } + } catch (e) { + spinner.fail(e.toString()); + throw e; + } + spinner.succeed( + `Successfully pushed dist-tag ${argv.tag} for ${pkgName} to npm` + ); + } + } + + console.log('\n\nโœ… All done'); + } +} + +main(); diff --git a/compiler/scripts/release/shared/build-packages.js b/compiler/scripts/release/shared/build-packages.js new file mode 100644 index 000000000000..0a5ac1f5c2b5 --- /dev/null +++ b/compiler/scripts/release/shared/build-packages.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const ora = require('ora'); +const {execHelper} = require('./utils'); + +async function buildPackages(pkgNames) { + const spinner = ora(`Building packages`).info(); + for (const pkgName of pkgNames) { + const command = `NODE_ENV=production yarn workspace ${pkgName} run build --dts`; + spinner.start(`Running: ${command}\n`); + try { + await execHelper(command); + } catch (e) { + spinner.fail(e.toString()); + throw e; + } + spinner.succeed(`Successfully built ${pkgName}`); + } + spinner.stop(); +} + +module.exports = { + buildPackages, +}; diff --git a/compiler/scripts/release/shared/packages.js b/compiler/scripts/release/shared/packages.js new file mode 100644 index 000000000000..235ba0f1ddb5 --- /dev/null +++ b/compiler/scripts/release/shared/packages.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const PUBLISHABLE_PACKAGES = [ + 'babel-plugin-react-compiler', + 'react-compiler-healthcheck', + 'react-compiler-runtime', +]; + +module.exports = { + PUBLISHABLE_PACKAGES, +}; diff --git a/compiler/scripts/release/shared/utils.js b/compiler/scripts/release/shared/utils.js new file mode 100644 index 000000000000..bda2d28c032c --- /dev/null +++ b/compiler/scripts/release/shared/utils.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const cp = require('child_process'); +const util = require('util'); + +function execHelper(command, options, streamStdout = false) { + return new Promise((resolve, reject) => { + const proc = cp.exec(command, options, (error, stdout) => + error ? reject(error) : resolve(stdout.trim()) + ); + if (streamStdout) { + proc.stdout.pipe(process.stdout); + } + }); +} + +function _spawn(command, args, options, cb) { + const child = cp.spawn(command, args, options); + child.on('close', exitCode => { + cb(null, exitCode); + }); + return child; +} +const spawnHelper = util.promisify(_spawn); + +async function getDateStringForCommit(commit) { + let dateString = await execHelper( + `git show -s --no-show-signature --format=%cd --date=format:%Y%m%d ${commit}` + ); + + // On CI environment, this string is wrapped with quotes '...'s + if (dateString.startsWith("'")) { + dateString = dateString.slice(1, 9); + } + + return dateString; +} + +module.exports = { + execHelper, + spawnHelper, + getDateStringForCommit, +}; diff --git a/compiler/scripts/test-babel-ast.sh b/compiler/scripts/test-babel-ast.sh new file mode 100755 index 000000000000..f2f23ff2c244 --- /dev/null +++ b/compiler/scripts/test-babel-ast.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +FIXTURE_SRC_DIR="$1" +if [ -z "$FIXTURE_SRC_DIR" ]; then + # Default: the compiler's own test fixtures + FIXTURE_SRC_DIR="$REPO_ROOT/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures" +fi + +# Parse source files into JSON in a temp directory +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +echo "Parsing fixtures from $FIXTURE_SRC_DIR..." +node "$REPO_ROOT/compiler/scripts/babel-ast-to-json.mjs" "$FIXTURE_SRC_DIR" "$TMPDIR" + +# Bump the default 8 MiB Rust thread stack to 32 MiB. The round_trip test +# walks deeply-nested Babel AST fixtures via recursive serde Visitor; some +# fixtures exceed the default stack on Linux CI runners. RUST_MIN_STACK only +# affects threads spawned via std::thread (which is how the libtest harness +# runs each test), so this is enough without changing the test sources. +export RUST_MIN_STACK=33554432 + +echo "Running round-trip test..." +cd "$REPO_ROOT/compiler/crates" +FIXTURE_JSON_DIR="$TMPDIR" ~/.cargo/bin/cargo test -p react_compiler_ast --test round_trip -- --nocapture + +echo "Running scope resolution test..." +FIXTURE_JSON_DIR="$TMPDIR" ~/.cargo/bin/cargo test -p react_compiler_ast --test scope_resolution -- --nocapture diff --git a/compiler/scripts/test-e2e.sh b/compiler/scripts/test-e2e.sh new file mode 100755 index 000000000000..5f23de648a45 --- /dev/null +++ b/compiler/scripts/test-e2e.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# End-to-end test runner comparing the Rust compiler (Babel/NAPI bridge) +# against the TS reference plugin. +# +# Usage: bash compiler/scripts/test-e2e.sh [fixtures-path] [--variant babel] [--limit N] [--no-color] + +set -eo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +exec npx tsx "$REPO_ROOT/compiler/scripts/test-e2e.ts" "$@" diff --git a/compiler/scripts/test-e2e.ts b/compiler/scripts/test-e2e.ts new file mode 100644 index 000000000000..446475eeaa7a --- /dev/null +++ b/compiler/scripts/test-e2e.ts @@ -0,0 +1,558 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * End-to-end test script comparing the Rust compiler against the TS reference. + * + * Runs fixtures through: + * - TS baseline (Babel plugin, in-process) โ€” the reference output + * - babel variant: Rust via Babel plugin (in-process via NAPI) โ€” the + * production path + * + * This complements `yarn snap --rust` by independently comparing the NAPI + * bridge's code output AND its logged events against the TS plugin. + * + * Usage: npx tsx compiler/scripts/test-e2e.ts [fixtures-path] [--variant babel] [--limit N] [--no-color] + */ + +import * as babel from '@babel/core'; +import generate from '@babel/generator'; +import {execSync} from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import prettier from 'prettier'; + +import {parseConfigPragmaForTests} from '../packages/babel-plugin-react-compiler/src/Utils/TestUtils'; + +const REPO_ROOT = path.resolve(__dirname, '../..'); + +// --- Parse flags --- +const rawArgs = process.argv.slice(2); +const noColor = rawArgs.includes('--no-color') || !!process.env.NO_COLOR; +const variantIdx = rawArgs.indexOf('--variant'); +const variantArg = + variantIdx >= 0 ? (rawArgs[variantIdx + 1] as 'babel') : null; +const limitIdx = rawArgs.indexOf('--limit'); +const limitArg = limitIdx >= 0 ? parseInt(rawArgs[limitIdx + 1], 10) : 50; + +// Extract positional args (strip flags and flag values) +const skipIndices = new Set(); +for (const flag of ['--no-color']) { + const idx = rawArgs.indexOf(flag); + if (idx >= 0) skipIndices.add(idx); +} +for (const flag of ['--variant', '--limit']) { + const idx = rawArgs.indexOf(flag); + if (idx >= 0) { + skipIndices.add(idx); + skipIndices.add(idx + 1); + } +} +const positional = rawArgs.filter((_a, i) => !skipIndices.has(i)); + +// --- ANSI colors --- +const useColor = !noColor; +const RED = useColor ? '\x1b[0;31m' : ''; +const GREEN = useColor ? '\x1b[0;32m' : ''; +const YELLOW = useColor ? '\x1b[0;33m' : ''; +const BOLD = useColor ? '\x1b[1m' : ''; +const DIM = useColor ? '\x1b[2m' : ''; +const RESET = useColor ? '\x1b[0m' : ''; + +// --- Fixtures --- +const DEFAULT_FIXTURES_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler', +); + +const fixturesPath = positional[0] + ? path.resolve(positional[0]) + : DEFAULT_FIXTURES_DIR; + +function discoverFixtures(rootPath: string): string[] { + const stat = fs.statSync(rootPath); + if (stat.isFile()) { + return [rootPath]; + } + + const results: string[] = []; + function walk(dir: string): void { + for (const entry of fs.readdirSync(dir, {withFileTypes: true})) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walk(fullPath); + } else if ( + /\.(js|jsx|ts|tsx)$/.test(entry.name) && + !entry.name.endsWith('.expect.md') + ) { + results.push(fullPath); + } + } + } + walk(rootPath); + results.sort(); + return results; +} + +// --- Build --- +console.log('Building Rust native module...'); +try { + execSync('~/.cargo/bin/cargo build -p react_compiler_napi', { + cwd: path.join(REPO_ROOT, 'compiler/crates'), + stdio: ['inherit', 'pipe', 'pipe'], + shell: true, + }); +} catch (e: any) { + // Show stderr on build failure (includes errors + warnings) + if (e.stderr) { + process.stderr.write(e.stderr); + } + console.error(`${RED}ERROR: Failed to build Rust crates.${RESET}`); + process.exit(1); +} + +// Copy the built dylib as index.node +const NATIVE_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler-rust/native', +); +const NATIVE_NODE_PATH = path.join(NATIVE_DIR, 'index.node'); +const TARGET_DIR = path.join(REPO_ROOT, 'compiler/target/debug'); +const dylib = fs.existsSync( + path.join(TARGET_DIR, 'libreact_compiler_napi.dylib'), +) + ? path.join(TARGET_DIR, 'libreact_compiler_napi.dylib') + : path.join(TARGET_DIR, 'libreact_compiler_napi.so'); + +if (!fs.existsSync(dylib)) { + console.error( + `${RED}ERROR: Could not find built native module in ${TARGET_DIR}${RESET}`, + ); + process.exit(1); +} +fs.copyFileSync(dylib, NATIVE_NODE_PATH); + +// --- Load plugins --- +const tsPlugin = require('../packages/babel-plugin-react-compiler/src').default; +const rustPlugin = + require('../packages/babel-plugin-react-compiler-rust/src').default; + +// --- Normalize code for comparison --- +// Reparse with Babel and regenerate with compact:true to erase all +// whitespace/formatting differences, then Prettier for readable output. +async function formatCode(code: string, isFlow: boolean): Promise { + try { + const parserPlugins: string[] = isFlow + ? ['flow', 'jsx'] + : ['typescript', 'jsx', 'explicitResourceManagement']; + const ast = babel.parseSync(code, { + sourceType: 'module', + parserOpts: {plugins: parserPlugins}, + configFile: false, + babelrc: false, + }); + if (!ast) return code; + const compact = generate(ast, {compact: true}).code; + return await prettier.format(compact, { + semi: true, + parser: isFlow ? 'flow' : 'babel-ts', + }); + } catch { + return code; + } +} + +// --- Compile via Babel plugin --- +type CompileResult = { + code: string | null; + error: string | null; + events: Array>; +}; + +function compileBabel( + plugin: any, + fixturePath: string, + source: string, + firstLine: string, +): CompileResult { + const isFlow = firstLine.includes('@flow'); + const isScript = firstLine.includes('@script'); + const parserPlugins: string[] = isFlow + ? ['flow', 'jsx'] + : ['typescript', 'jsx', 'explicitResourceManagement']; + + const pragmaOpts = parseConfigPragmaForTests(firstLine, { + compilationMode: 'all', + }); + + const events: Array> = []; + const pluginOptions = { + ...pragmaOpts, + compilationMode: 'all' as const, + panicThreshold: 'all_errors' as const, + logger: { + logEvent(_filename: string | null, event: Record): void { + events.push(event); + }, + debugLogIRs(): void {}, + }, + }; + + try { + const result = babel.transformSync(source, { + filename: fixturePath, + sourceType: isScript ? 'script' : 'module', + parserOpts: {plugins: parserPlugins}, + plugins: [[plugin, pluginOptions]], + configFile: false, + babelrc: false, + }); + return {code: result?.code ?? null, error: null, events}; + } catch (e) { + return { + code: null, + error: e instanceof Error ? e.message : String(e), + events, + }; + } +} + +// --- Event normalization --- +// Strip identifierName (Babel-specific SourceLocation property), sort +// keys for stable comparison, then JSON.stringify. Both the TS plugin and +// the Rust NAPI bridge emit 0-based columns/indices, so no positional +// adjustment is needed. +const STRIP_KEYS = new Set(['identifierName', 'fnLoc']); + +function sortAndStrip(obj: unknown): unknown { + if (obj === null || typeof obj !== 'object') return obj; + if (Array.isArray(obj)) return obj.map(sortAndStrip); + const sorted: Record = {}; + for (const key of Object.keys(obj as Record).sort()) { + if (STRIP_KEYS.has(key)) continue; + sorted[key] = sortAndStrip((obj as Record)[key]); + } + return sorted; +} + +function stripPipelineErrorStack( + events: Array>, +): Array> { + return events.map(event => { + if (event.kind !== 'PipelineError') return event; + const data = event.data; + if (typeof data !== 'string') return event; + // Strip JS stack trace: keep only the message (before first "\n at ") + const idx = data.indexOf('\n at '); + return {...event, data: idx >= 0 ? data.substring(0, idx) : data}; + }); +} + +function normalizeEvents(events: Array>): string { + return JSON.stringify(sortAndStrip(stripPipelineErrorStack(events)), null, 2); +} + +// --- Simple unified diff --- +function unifiedDiff( + expected: string, + actual: string, + leftLabel: string, + rightLabel: string, +): string { + const expectedLines = expected.split('\n'); + const actualLines = actual.split('\n'); + const lines: string[] = []; + lines.push(`${RED}--- ${leftLabel}${RESET}`); + lines.push(`${GREEN}+++ ${rightLabel}${RESET}`); + + const maxLen = Math.max(expectedLines.length, actualLines.length); + let contextStart = -1; + for (let i = 0; i < maxLen; i++) { + const eLine = i < expectedLines.length ? expectedLines[i] : undefined; + const aLine = i < actualLines.length ? actualLines[i] : undefined; + if (eLine === aLine) continue; + if (contextStart !== i) { + lines.push(`${YELLOW}@@ line ${i + 1} @@${RESET}`); + } + contextStart = i + 1; + if (eLine !== undefined && aLine !== undefined) { + lines.push(`${RED}-${eLine}${RESET}`); + lines.push(`${GREEN}+${aLine}${RESET}`); + } else if (eLine !== undefined) { + lines.push(`${RED}-${eLine}${RESET}`); + } else if (aLine !== undefined) { + lines.push(`${GREEN}+${aLine}${RESET}`); + } + } + return lines.join('\n'); +} + +// --- Main --- +type Variant = 'babel'; +const ALL_VARIANTS: Variant[] = ['babel']; +const variants: Variant[] = variantArg ? [variantArg] : ALL_VARIANTS; + +const fixtures = discoverFixtures(fixturesPath); +if (fixtures.length === 0) { + console.error('No fixtures found at', fixturesPath); + process.exit(1); +} + +interface VariantStats { + passed: number; + failed: number; + codePassed: number; + codeFailed: number; + eventsPassed: number; + eventsFailed: number; + failures: Array<{fixture: string; detail: string}>; + failedFixtures: string[]; +} + +function makeStats(): VariantStats { + return { + passed: 0, + failed: 0, + codePassed: 0, + codeFailed: 0, + eventsPassed: 0, + eventsFailed: 0, + failures: [], + failedFixtures: [], + }; +} + +// --- Progress helper --- +function writeProgress(msg: string): void { + if (process.stderr.isTTY) { + process.stderr.write(`\r\x1b[K${msg}`); + } +} + +function clearProgress(): void { + if (process.stderr.isTTY) { + process.stderr.write('\r\x1b[K'); + } +} + +// --- Pre-compute TS baselines (shared across variants) --- +interface FixtureInfo { + fixturePath: string; + relPath: string; + source: string; + firstLine: string; + isFlow: boolean; +} + +async function runVariant( + variant: Variant, + fixtureInfos: FixtureInfo[], + tsBaselines: Map, + tsRawEvents: Map>>, + s: VariantStats, +): Promise { + for (let i = 0; i < fixtureInfos.length; i++) { + const {fixturePath, relPath, source, firstLine, isFlow} = fixtureInfos[i]; + const tsCode = tsBaselines.get(fixturePath)!; + const tsEvents = normalizeEvents(tsRawEvents.get(fixturePath)!); + + writeProgress( + ` ${variant}: ${i + 1}/${fixtureInfos.length} (${s.passed} passed, ${ + s.failed + } failed)`, + ); + + const variantResult = compileBabel( + rustPlugin, + fixturePath, + source, + firstLine, + ); + + const variantCode = await formatCode(variantResult.code ?? '', isFlow); + const variantEvents = normalizeEvents(variantResult.events); + + // When both TS and the variant error (produce empty/no output), count as pass. + const tsErrored = tsCode.trim() === ''; + const variantErrored = + variantCode.trim() === '' || variantResult.error != null; + + const codeMatch = tsCode === variantCode || (tsErrored && variantErrored); + const eventsMatch = tsEvents === variantEvents; + + // When code doesn't match due to TS error + variant passthrough, check + // if the variant output is just uncompiled source (no memoization). + let codePassthrough = false; + if (!codeMatch && tsErrored && variantCode.trim() !== '') { + const variantHasMemoization = + variantCode.includes('_c(') || variantCode.includes('useMemoCache'); + if (!variantHasMemoization) { + codePassthrough = true; + } + } + + const codeOk = codeMatch || codePassthrough; + if (codeOk) { + s.codePassed++; + } else { + s.codeFailed++; + } + if (eventsMatch) { + s.eventsPassed++; + } else { + s.eventsFailed++; + } + + if (codeOk && eventsMatch) { + s.passed++; + } else { + s.failed++; + s.failedFixtures.push(relPath); + if (limitArg === 0 || s.failures.length < limitArg) { + const details: string[] = []; + if (!codeOk) { + details.push(unifiedDiff(tsCode, variantCode, 'TypeScript', variant)); + } + if (!eventsMatch) { + details.push( + unifiedDiff( + tsEvents, + variantEvents, + 'TS events', + variant + ' events', + ), + ); + } + s.failures.push({ + fixture: relPath, + detail: details.join('\n\n'), + }); + } + } + } + clearProgress(); +} + +(async () => { + const stats = new Map(); + for (const v of variants) { + stats.set(v, makeStats()); + } + + if (variantArg) { + console.log( + `Testing ${BOLD}${fixtures.length}${RESET} fixtures: TS baseline vs ${BOLD}${variantArg}${RESET}`, + ); + } else { + console.log( + `Testing ${BOLD}${fixtures.length}${RESET} fixtures across all variants`, + ); + } + console.log(''); + + // Pre-compute fixture info and TS baselines + const fixtureInfos: FixtureInfo[] = []; + const tsBaselines = new Map(); + const tsRawEvents = new Map>>(); + + console.log('Computing TS baselines...'); + for (let i = 0; i < fixtures.length; i++) { + const fixturePath = fixtures[i]; + const relPath = path.relative(REPO_ROOT, fixturePath); + const source = fs.readFileSync(fixturePath, 'utf8'); + const firstLine = source.substring(0, source.indexOf('\n')); + const isFlow = firstLine.includes('@flow'); + + writeProgress(` baseline: ${i + 1}/${fixtures.length}`); + + const tsResult = compileBabel(tsPlugin, fixturePath, source, firstLine); + const tsCode = await formatCode(tsResult.code ?? '', isFlow); + + fixtureInfos.push({fixturePath, relPath, source, firstLine, isFlow}); + tsBaselines.set(fixturePath, tsCode); + tsRawEvents.set(fixturePath, tsResult.events); + } + clearProgress(); + console.log(`Computed ${fixtures.length} baselines.`); + console.log(''); + + // Run each variant + for (const variant of variants) { + console.log(`Running ${BOLD}${variant}${RESET} variant...`); + await runVariant( + variant, + fixtureInfos, + tsBaselines, + tsRawEvents, + stats.get(variant)!, + ); + const s = stats.get(variant)!; + console.log(` ${s.passed} passed, ${s.failed} failed`); + } + console.log(''); + + // --- Output --- + if (variantArg) { + // Single variant mode: show diffs + const s = stats.get(variantArg)!; + const total = fixtures.length; + const summaryColor = s.failed === 0 ? GREEN : RED; + const summary = + `Code: ${s.codePassed}/${total} passed ` + + `Events: ${s.eventsPassed}/${total} passed ` + + `Total: ${s.passed}/${total} passed`; + console.log(`${summaryColor}${summary}${RESET}`); + console.log(''); + + for (const failure of s.failures) { + console.log(`${RED}FAIL${RESET} ${failure.fixture}`); + console.log(failure.detail); + console.log(''); + } + + if (s.failures.length < s.failed) { + console.log( + `${DIM} (showing first ${s.failures.length} of ${s.failed} failures)${RESET}`, + ); + } + + console.log('---'); + console.log(`${summaryColor}${summary}${RESET}`); + } else { + // Summary table mode + const total = fixtures.length; + + function fmtCell(passed: number, total: number): string { + const pct = ((passed / total) * 100).toFixed(1); + return `${passed}/${total} (${pct}%)`; + } + + // Table header + const colW = 22; + const hdr = + `${'Variant'.padEnd(10)} ` + + `${'Code'.padEnd(colW)} ` + + `${'Events'.padEnd(colW)} ` + + `${'Total'.padEnd(colW)}`; + console.log(`${BOLD}${hdr}${RESET}`); + + for (const variant of ALL_VARIANTS) { + const s = stats.get(variant)!; + const line = + `${variant.padEnd(10)} ` + + `${fmtCell(s.codePassed, total).padEnd(colW)} ` + + `${fmtCell(s.eventsPassed, total).padEnd(colW)} ` + + `${fmtCell(s.passed, total)}`; + const color = s.failed === 0 ? GREEN : s.passed === 0 ? RED : YELLOW; + console.log(`${color}${line}${RESET}`); + } + } + + // Exit with failure if any variant has failures + const anyFailed = [...stats.values()].some(s => s.failed > 0); + process.exit(anyFailed ? 1 : 0); +})(); diff --git a/compiler/scripts/test-internal-files.sh b/compiler/scripts/test-internal-files.sh new file mode 100755 index 000000000000..032be8c1584b --- /dev/null +++ b/compiler/scripts/test-internal-files.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Compare TS and Rust React Compiler output on external production files. +# +# Usage: bash compiler/scripts/test-internal-files.sh [flags] +# Flags: --limit N, --pattern PAT, --project NAME, --dry-run, --no-color + +set -eo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +exec npx tsx "$REPO_ROOT/compiler/scripts/test-internal-files.ts" "$@" diff --git a/compiler/scripts/test-internal-files.ts b/compiler/scripts/test-internal-files.ts new file mode 100644 index 000000000000..74e7a5910759 --- /dev/null +++ b/compiler/scripts/test-internal-files.ts @@ -0,0 +1,724 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Compare TS and Rust React Compiler output on external production files. + * + * Given a configuration module and a source root directory, compiles files + * using the exact plugin options from the configuration, then compares code + * output and error events between the TS and Rust compilers. Files with + * differences can be copied as test fixtures for further investigation. + * + * Usage: + * npx tsx compiler/scripts/test-internal-files.ts [flags] + * + * Arguments: + * Path to the compiler configuration module (JS file that + * exports getForgetConfiguration and config) + * Root directory from which the config's source prefixes + * are resolved + * + * Flags: + * --limit N Max files to process (default: 0 = all) + * --pattern PAT Filter file paths (substring match) + * --project NAME Filter by project name from config + * --dry-run Compare only, skip fixture creation + * --no-color Disable ANSI color codes + */ + +import * as babel from '@babel/core'; +import hermesParserPlugin from 'babel-plugin-syntax-hermes-parser'; +import {execSync} from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import prettier from 'prettier'; + +const REPO_ROOT = path.resolve(__dirname, '../..'); +const FIXTURE_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/internal', +); + +// --- Parse flags and positional args --- +const rawArgs = process.argv.slice(2); +const noColor = rawArgs.includes('--no-color') || !!process.env.NO_COLOR; +const dryRun = rawArgs.includes('--dry-run'); +const limitIdx = rawArgs.indexOf('--limit'); +const limitArg = limitIdx >= 0 ? parseInt(rawArgs[limitIdx + 1], 10) : 0; +const patternIdx = rawArgs.indexOf('--pattern'); +const patternArg = patternIdx >= 0 ? rawArgs[patternIdx + 1] : null; +const projectIdx = rawArgs.indexOf('--project'); +const projectArg = projectIdx >= 0 ? rawArgs[projectIdx + 1] : null; + +// Collect flag indices to exclude from positional args +const flagValueIndices = new Set(); +if (limitIdx >= 0) flagValueIndices.add(limitIdx + 1); +if (patternIdx >= 0) flagValueIndices.add(patternIdx + 1); +if (projectIdx >= 0) flagValueIndices.add(projectIdx + 1); +const positional = rawArgs.filter( + (a, i) => !a.startsWith('--') && !flagValueIndices.has(i), +); + +if (positional.length < 2) { + console.error( + 'Usage: npx tsx compiler/scripts/test-internal-files.ts [flags]', + ); + console.error(''); + console.error('Arguments:'); + console.error(' Path to the compiler configuration module'); + console.error( + ' Root directory for resolving config source prefixes', + ); + console.error(''); + console.error('Flags:'); + console.error(' --limit N Max files to process'); + console.error(' --pattern PAT Filter file paths (substring match)'); + console.error(' --project NAME Filter by project name from config'); + console.error(' --dry-run Compare only, skip fixture creation'); + console.error(' --no-color Disable ANSI color codes'); + process.exit(1); +} + +const configPath = path.resolve(positional[0]); +const sourceRoot = path.resolve(positional[1]); + +// --- ANSI colors --- +const RED = noColor ? '' : '\x1b[0;31m'; +const GREEN = noColor ? '' : '\x1b[0;32m'; +const YELLOW = noColor ? '' : '\x1b[0;33m'; +const BOLD = noColor ? '' : '\x1b[1m'; +const DIM = noColor ? '' : '\x1b[2m'; +const RESET = noColor ? '' : '\x1b[0m'; + +// --- Load config --- +if (!fs.existsSync(configPath)) { + console.error(`${RED}ERROR: Could not find config at ${configPath}${RESET}`); + process.exit(1); +} +if (!fs.existsSync(sourceRoot) || !fs.statSync(sourceRoot).isDirectory()) { + console.error( + `${RED}ERROR: Source root is not a valid directory: ${sourceRoot}${RESET}`, + ); + process.exit(1); +} +const forgetConfig = require(configPath); +const {getForgetConfiguration, config: rawConfig} = forgetConfig; + +// --- Build native module --- +const NATIVE_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler-rust/native', +); +const NATIVE_NODE_PATH = path.join(NATIVE_DIR, 'index.node'); + +console.log('Building Rust native module...'); +try { + execSync('~/.cargo/bin/cargo build -p react_compiler_napi', { + cwd: path.join(REPO_ROOT, 'compiler/crates'), + stdio: 'inherit', + shell: true, + }); +} catch { + console.error(`${RED}ERROR: Failed to build Rust native module.${RESET}`); + process.exit(1); +} + +const TARGET_DIR = path.join(REPO_ROOT, 'compiler/target/debug'); +const dylib = fs.existsSync( + path.join(TARGET_DIR, 'libreact_compiler_napi.dylib'), +) + ? path.join(TARGET_DIR, 'libreact_compiler_napi.dylib') + : path.join(TARGET_DIR, 'libreact_compiler_napi.so'); + +if (!fs.existsSync(dylib)) { + console.error( + `${RED}ERROR: Could not find built native module in ${TARGET_DIR}${RESET}`, + ); + process.exit(1); +} +fs.copyFileSync(dylib, NATIVE_NODE_PATH); + +// --- Load plugins --- +const tsPlugin = require('../packages/babel-plugin-react-compiler/src').default; +const rustPlugin = + require('../packages/babel-plugin-react-compiler-rust/src').default; + +// --- Types --- +interface LoggerEvent { + kind: string; + fnName?: string | null; + fnLoc?: unknown; + reason?: string; + detail?: { + reason?: string; + severity?: string; + category?: string; + description?: string; + }; + data?: string; +} + +interface CompileResult { + code: string | null; + events: LoggerEvent[]; + error: string | null; +} + +interface FileEntry { + filePath: string; + projectName: string; + projectConfig: Record; +} + +// --- File discovery --- +// Additional directory exclusions beyond what the config handles +const EXTRA_EXCLUDES = [ + '__server_snapshot_tests__', + '__e2e_tests__', + '__perf_tests__', + '__integration_tests__', +]; + +function walkDir(dir: string, callback: (filePath: string) => void): void { + let entries: fs.Dirent[]; + try { + entries = fs.readdirSync(dir, {withFileTypes: true}); + } catch { + return; + } + for (const entry of entries) { + if (EXTRA_EXCLUDES.includes(entry.name)) continue; + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walkDir(fullPath, callback); + } else if (/\.(js|jsx)$/.test(entry.name)) { + callback(fullPath); + } + } +} + +function discoverFiles(): FileEntry[] { + console.log('Discovering files...'); + const results: FileEntry[] = []; + const seen = new Set(); + + for (const [prefix, projectName] of Object.entries( + rawConfig.sources as Record, + )) { + if (projectArg && projectName !== projectArg) continue; + + // Resolve prefix to absolute path relative to source root + const absPrefix = path.join(sourceRoot, prefix); + if (!fs.existsSync(absPrefix)) continue; + + const stat = fs.statSync(absPrefix); + if (!stat.isDirectory()) continue; + + walkDir(absPrefix, filePath => { + if (seen.has(filePath)) return; + seen.add(filePath); + + if (patternArg && !filePath.includes(patternArg)) return; + + const config = getForgetConfiguration(filePath); + if (config == null || !config.enable) return; + + results.push({filePath, projectName, projectConfig: config}); + }); + + if (limitArg > 0 && results.length >= limitArg) break; + } + + if (limitArg > 0) { + return results.slice(0, limitArg); + } + return results; +} + +// --- Build plugin options from production config --- +function makePluginOptions( + projectConfig: Record, + logger: {logEvent: (filename: string | null, event: LoggerEvent) => void}, +): Record { + return { + compilationMode: projectConfig.compilationMode, + panicThreshold: 'none', + environment: projectConfig.environment, + target: + projectConfig.compilerVersion === 'experimental' + ? projectConfig.target + : projectConfig.target, + gating: null, + flowSuppressions: projectConfig.flowSuppressions, + enableReanimatedCheck: false, + logger, + sources: null, + }; +} + +// --- Compile a file --- +function compileFile( + mode: 'ts' | 'rust', + filePath: string, + pluginOptions: Record, +): CompileResult { + const source = fs.readFileSync(filePath, 'utf8'); + const events: LoggerEvent[] = []; + + const logger = { + logEvent(_filename: string | null, event: LoggerEvent): void { + events.push(event); + }, + }; + + const opts = {...pluginOptions, logger}; + const plugin = mode === 'ts' ? tsPlugin : rustPlugin; + + try { + const result = babel.transformSync(source, { + filename: filePath, + sourceType: 'module', + plugins: [hermesParserPlugin, [plugin, opts]], + configFile: false, + babelrc: false, + }); + return {code: result?.code ?? null, events, error: null}; + } catch (e) { + const msg = e instanceof Error ? e.message : String(e); + return {code: null, events, error: msg}; + } +} + +// --- Format events for comparison --- +function formatEvents(events: LoggerEvent[]): string { + return events + .filter(e => + [ + 'CompileError', + 'CompileSkip', + 'CompileSuccess', + 'PipelineError', + ].includes(e.kind), + ) + .map(e => { + if (e.kind === 'CompileSuccess') { + return `[CompileSuccess] ${e.fnName ?? '(anonymous)'}`; + } + if (e.kind === 'CompileError') { + const d = e.detail; + return `[CompileError] ${d?.reason ?? '(no reason)'} (${d?.severity ?? ''}, ${d?.category ?? ''})`; + } + if (e.kind === 'CompileSkip') { + return `[CompileSkip] ${e.reason ?? '(no reason)'}`; + } + return `[${e.kind}] ${e.data ?? ''}`; + }) + .join('\n'); +} + +// --- Simple diff --- +function unifiedDiff(expected: string, actual: string): string { + const expectedLines = expected.split('\n'); + const actualLines = actual.split('\n'); + const lines: string[] = []; + lines.push(`${RED}--- TS${RESET}`); + lines.push(`${GREEN}+++ Rust${RESET}`); + + const maxLen = Math.max(expectedLines.length, actualLines.length); + let contextStart = -1; + for (let i = 0; i < maxLen; i++) { + const eLine = i < expectedLines.length ? expectedLines[i] : undefined; + const aLine = i < actualLines.length ? actualLines[i] : undefined; + if (eLine === aLine) continue; + if (contextStart !== i) { + lines.push(`${YELLOW}@@ line ${i + 1} @@${RESET}`); + } + contextStart = i + 1; + if (eLine !== undefined) lines.push(`${RED}-${eLine}${RESET}`); + if (aLine !== undefined) lines.push(`${GREEN}+${aLine}${RESET}`); + } + return lines.join('\n'); +} + +// --- Format code with prettier --- +async function formatCode(code: string): Promise { + return prettier.format(code, {semi: true, parser: 'flow'}); +} + +// --- Generate pragma line for fixture --- +function generatePragma( + projectConfig: Record, + isFlow: boolean, +): string { + const parts: string[] = []; + + // The snap tool checks the first line for @flow to determine parser + if (isFlow) { + parts.push('@flow'); + } + + // compilationMode + const mode = projectConfig.compilationMode as string; + if (mode && mode !== 'all') { + parts.push(`@compilationMode:"${mode}"`); + } + + // Environment options + const env = (projectConfig.environment ?? {}) as Record; + + if (env.enableAssumeHooksFollowRulesOfReact === true) { + parts.push('@enableAssumeHooksFollowRulesOfReact'); + } + if (env.enableTransitivelyFreezeFunctionExpressions === true) { + parts.push('@enableTransitivelyFreezeFunctionExpressions'); + } + if (env.validatePreserveExistingMemoizationGuarantees === true) { + parts.push('@validatePreserveExistingMemoizationGuarantees'); + } + if (env.enableFunctionOutlining === false) { + parts.push('@enableFunctionOutlining:false'); + } + if ( + Array.isArray(env.validateNoCapitalizedCalls) && + env.validateNoCapitalizedCalls.length > 0 + ) { + parts.push( + `@validateNoCapitalizedCalls:${JSON.stringify(env.validateNoCapitalizedCalls)}`, + ); + } + + // target for experimental projects + if (projectConfig.compilerVersion === 'experimental') { + parts.push('@target:"donotuse_meta_internal"'); + } + + return parts.length > 0 ? '// ' + parts.join(' ') : ''; +} + +// --- Create fixture file and baseline .expect.md --- +async function createFixture( + filePath: string, + projectName: string, + projectConfig: Record, + tsCode: string | null, + tsError: string | null, +): Promise { + fs.mkdirSync(FIXTURE_DIR, {recursive: true}); + + const basename = path.basename(filePath); + const ext = path.extname(basename); + const stem = basename.slice(0, -ext.length); + let fixtureName = `${projectName}--${basename}`; + + // Deduplicate + let counter = 0; + while (fs.existsSync(path.join(FIXTURE_DIR, fixtureName))) { + counter++; + fixtureName = `${projectName}--${stem}-${counter}${ext}`; + } + + const source = fs.readFileSync(filePath, 'utf8'); + const headerBlock = source.substring(0, source.indexOf('*/') + 2 || 200); + const isFlow = headerBlock.includes('@flow'); + const pragma = generatePragma(projectConfig, isFlow); + + const content = pragma ? `${pragma}\n${source}` : source; + + const fixturePath = path.join(FIXTURE_DIR, fixtureName); + fs.writeFileSync(fixturePath, content, 'utf8'); + + // Generate .expect.md baseline from TS compiler output. + // This bypasses yarn snap -u (which fails due to sprout evaluator + // not being able to resolve internal module imports). + // Format matches snap's writeOutputToString in reporter.ts. + let formattedCode: string | null = null; + if (tsCode != null) { + try { + formattedCode = await formatCode(tsCode); + } catch { + formattedCode = tsCode; + } + } + + let expectMd = `\n## Input\n\n\`\`\`javascript\n${content}\n\`\`\`\n`; + if (formattedCode != null) { + expectMd += `\n## Code\n\n\`\`\`javascript\n${formattedCode}\`\`\`\n`; + } else { + expectMd += '\n'; + } + if (tsError != null) { + const cleanError = tsError.replace(/^\/.*?:\s/, ''); + expectMd += `\n## Error\n\n\`\`\`\n${cleanError}\n\`\`\`\n \n`; + } + expectMd += ` `; + + const expectPath = fixturePath.replace(/\.[^.]+$/, '.expect.md'); + fs.writeFileSync(expectPath, expectMd, 'utf8'); + + return fixturePath; +} + +// --- Main --- +(async () => { + const files = discoverFiles(); + if (files.length === 0) { + console.error('No files found matching filters.'); + process.exit(1); + } + + console.log( + `\nComparing ${BOLD}${files.length}${RESET} files (TS vs Rust)...\n`, + ); + + // Crash recovery: maintain a skip list of files that segfault the native module. + // On crash, the current file is appended to the skip list. + // On subsequent runs, those files are skipped automatically. + const crashLogPath = path.join( + REPO_ROOT, + 'compiler/.test-internal-files-current', + ); + const skipListPath = path.join( + REPO_ROOT, + 'compiler/.test-internal-skip-list', + ); + const skipSet = new Set(); + try { + const skipData = fs.readFileSync(skipListPath, 'utf8'); + for (const line of skipData.split('\n')) { + const trimmed = line.trim(); + if (trimmed) skipSet.add(trimmed); + } + if (skipSet.size > 0) { + console.log( + `${DIM}Skipping ${skipSet.size} previously-crashing files${RESET}`, + ); + } + } catch {} + + process.on('exit', code => { + if (code === 139 || code === 134 || code === 11) { + // SIGSEGV or SIGABRT โ€” append the culprit to skip list + try { + const crashFile = fs.readFileSync(crashLogPath, 'utf8').trim(); + fs.appendFileSync(skipListPath, crashFile + '\n', 'utf8'); + console.error( + `\n${RED}CRASH (signal ${code}) on file: ${crashFile}${RESET}`, + ); + console.error( + `${YELLOW}File added to skip list. Re-run to continue.${RESET}`, + ); + } catch {} + } + try { + fs.unlinkSync(crashLogPath); + } catch {} + }); + + let processed = 0; + let codeDiffs = 0; + let eventDiffs = 0; + let bothErrored = 0; + let crashes = 0; + const diffFiles: Array<{ + filePath: string; + projectName: string; + projectConfig: Record; + codeDiff: string | null; + eventDiff: string | null; + tsCode: string | null; + tsError: string | null; + }> = []; + const createdFixtures: string[] = []; + + for (const {filePath, projectName, projectConfig} of files) { + if (skipSet.has(filePath)) continue; + processed++; + + // Write current file for crash identification + fs.writeFileSync(crashLogPath, filePath, 'utf8'); + + // Progress + const relPath = filePath.replace(sourceRoot + '/', ''); + process.stdout.write( + `\r${DIM}[${processed}/${files.length}] ${codeDiffs} code diffs, ${eventDiffs} event diffs, ${crashes} crashes${RESET} `, + ); + + const pluginOpts = makePluginOptions(projectConfig, { + logEvent() {}, + }); + + let tsResult: CompileResult; + let rustResult: CompileResult; + try { + tsResult = compileFile('ts', filePath, pluginOpts); + } catch (e) { + // Unexpected crash in TS compiler + tsResult = { + code: null, + events: [], + error: `TS crash: ${e instanceof Error ? e.message : String(e)}`, + }; + } + try { + rustResult = compileFile('rust', filePath, pluginOpts); + } catch (e) { + // Unexpected crash in Rust compiler + rustResult = { + code: null, + events: [], + error: `Rust crash: ${e instanceof Error ? e.message : String(e)}`, + }; + } + + // Compare code + let hasCodeDiff = false; + let codeDiffDetail: string | null = null; + try { + const tsCode = await formatCode(tsResult.code ?? ''); + const rustCode = await formatCode(rustResult.code ?? ''); + if (tsCode !== rustCode) { + hasCodeDiff = true; + codeDiffDetail = unifiedDiff(tsCode, rustCode); + } + } catch { + // Prettier failed โ€” compare raw + if ((tsResult.code ?? '') !== (rustResult.code ?? '')) { + hasCodeDiff = true; + codeDiffDetail = unifiedDiff( + tsResult.code ?? '', + rustResult.code ?? '', + ); + } + } + + // Compare error events + const tsEvents = formatEvents(tsResult.events); + const rustEvents = formatEvents(rustResult.events); + let hasEventDiff = false; + let eventDiffDetail: string | null = null; + if (tsEvents !== rustEvents) { + hasEventDiff = true; + eventDiffDetail = unifiedDiff(tsEvents, rustEvents); + } + + // Track errors + if (tsResult.error && rustResult.error) { + bothErrored++; + } + + if (hasCodeDiff || hasEventDiff) { + if (hasCodeDiff) codeDiffs++; + if (hasEventDiff) eventDiffs++; + diffFiles.push({ + filePath, + projectName, + projectConfig, + codeDiff: codeDiffDetail, + eventDiff: eventDiffDetail, + tsCode: tsResult.code, + tsError: tsResult.error, + }); + } + } + + // Clear progress line + process.stdout.write('\r' + ' '.repeat(80) + '\r'); + + // --- Report diffs --- + if (diffFiles.length > 0) { + console.log(`\n${BOLD}--- Differences ---${RESET}\n`); + const showLimit = 50; + const toShow = diffFiles.slice(0, showLimit); + + for (const entry of toShow) { + const relPath = entry.filePath.replace(sourceRoot + '/', ''); + console.log( + `${RED}DIFF${RESET} ${relPath} ${DIM}(${entry.projectName})${RESET}`, + ); + if (entry.codeDiff) { + console.log(entry.codeDiff); + } + if (entry.eventDiff) { + console.log(`${YELLOW}Event diff:${RESET}`); + console.log(entry.eventDiff); + } + console.log(''); + } + if (diffFiles.length > showLimit) { + console.log( + `${DIM}(showing first ${showLimit} of ${diffFiles.length} diffs)${RESET}`, + ); + } + } + + // --- Create fixtures --- + if (!dryRun && diffFiles.length > 0) { + console.log(`\n${BOLD}--- Creating fixtures ---${RESET}\n`); + + // Only create fixtures for files with code diffs (not event-only diffs) + const codeDiffFiles = diffFiles.filter(f => f.codeDiff != null); + + for (const entry of codeDiffFiles) { + const fixturePath = await createFixture( + entry.filePath, + entry.projectName, + entry.projectConfig, + entry.tsCode, + entry.tsError, + ); + createdFixtures.push(fixturePath); + const fixtureName = path.basename(fixturePath); + console.log(` ${GREEN}+${RESET} ${fixtureName}`); + } + + if (createdFixtures.length > 0) { + console.log( + `\nCreated ${BOLD}${createdFixtures.length}${RESET} fixtures in internal/`, + ); + + // --- Verification --- + console.log(`\n${BOLD}--- Verifying fixtures ---${RESET}\n`); + + // Verify with Rust compiler (baselines already written as .expect.md) + console.log('\nVerifying with yarn snap --rust ...'); + try { + execSync("yarn snap --rust -p 'internal/*'", { + cwd: path.join(REPO_ROOT, 'compiler'), + stdio: 'inherit', + }); + // If snap --rust passes, all fixtures matched (unexpected) + console.log( + `${YELLOW}WARNING: yarn snap --rust passed โ€” fixtures may not reproduce differences.${RESET}`, + ); + } catch { + // Expected: snap --rust should fail for differing fixtures + console.log( + `${GREEN}yarn snap --rust failed as expected โ€” fixtures reproduce differences.${RESET}`, + ); + } + + console.log( + `\n${RED}${BOLD}DO NOT COMMIT${RESET}${RED} the fixture files in internal/${RESET}`, + ); + } + } + + // --- Summary --- + console.log(`\n${BOLD}--- Summary ---${RESET}`); + console.log(`Processed: ${processed}`); + console.log(`Code diffs: ${codeDiffs}`); + console.log( + `Event-only diffs: ${eventDiffs - codeDiffs > 0 ? eventDiffs - codeDiffs : 0}`, + ); + console.log(`Both errored: ${bothErrored}`); + if (crashes > 0) console.log(`Crashes (skipped): ${crashes}`); + if (createdFixtures.length > 0) { + console.log(`Fixtures created: ${createdFixtures.length}`); + } + + process.exit(codeDiffs > 0 ? 1 : 0); +})(); diff --git a/compiler/scripts/test-rust-port.sh b/compiler/scripts/test-rust-port.sh new file mode 100755 index 000000000000..710479ad9100 --- /dev/null +++ b/compiler/scripts/test-rust-port.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Thin wrapper that delegates to the TS test script. +# The TS script handles building the native module itself. +# +# Usage: bash compiler/scripts/test-rust-port.sh [] [] [flags] +# Flags: --no-color, --json, --failures, --limit N, --mode MODE + +set -eo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +exec npx tsx "$REPO_ROOT/compiler/scripts/test-rust-port.ts" "$@" diff --git a/compiler/scripts/test-rust-port.ts b/compiler/scripts/test-rust-port.ts new file mode 100644 index 000000000000..ec737d9b8307 --- /dev/null +++ b/compiler/scripts/test-rust-port.ts @@ -0,0 +1,844 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Unified Babel plugin-based test script for comparing TS and Rust compilers. + * + * Runs both compilers through their real Babel plugins, captures debug log + * entries via the logger API, and diffs output for a specific pass. + * + * Usage: npx tsx compiler/scripts/test-rust-port.ts [] [] [flags] + * + * Flags: + * --no-color Disable ANSI color codes (also respects NO_COLOR env var) + * --json Output a single JSON object to stdout (machine-readable) + * --failures Print only failing fixture paths, one per line + * --limit N Max failures to display with diffs (default: 50, 0 = all) + * --mode MODE Compilation mode (default: use implementation default) + */ + +import * as babel from '@babel/core'; +import hermesParserPlugin from 'babel-plugin-syntax-hermes-parser'; +import {execSync} from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import prettier from 'prettier'; + +import {parseConfigPragmaForTests} from '../packages/babel-plugin-react-compiler/src/Utils/TestUtils'; +import {printDebugHIR} from '../packages/babel-plugin-react-compiler/src/HIR/DebugPrintHIR'; +import {printDebugReactiveFunction} from '../packages/babel-plugin-react-compiler/src/HIR/DebugPrintReactiveFunction'; +import type {CompilerPipelineValue} from '../packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline'; + +const REPO_ROOT = path.resolve(__dirname, '../..'); + +// --- Parse flags --- +const rawArgs = process.argv.slice(2); +const noColor = rawArgs.includes('--no-color') || !!process.env.NO_COLOR; +const jsonMode = rawArgs.includes('--json'); +const failuresMode = rawArgs.includes('--failures'); +const limitIdx = rawArgs.indexOf('--limit'); +const limitArg = limitIdx >= 0 ? parseInt(rawArgs[limitIdx + 1], 10) : 50; +const modeIdx = rawArgs.indexOf('--mode'); +const compilationModeArg: string | null = + modeIdx >= 0 ? rawArgs[modeIdx + 1] : null; + +// Extract positional args (strip flags and flag values) +const flagValueIndices = new Set(); +if (limitIdx >= 0) flagValueIndices.add(limitIdx + 1); +if (modeIdx >= 0) flagValueIndices.add(modeIdx + 1); +const positional = rawArgs.filter( + (a, i) => !a.startsWith('--') && !flagValueIndices.has(i), +); + +// --- ANSI colors --- +const useColor = !noColor && !jsonMode && !failuresMode; +const RED = useColor ? '\x1b[0;31m' : ''; +const GREEN = useColor ? '\x1b[0;32m' : ''; +const YELLOW = useColor ? '\x1b[0;33m' : ''; +const BOLD = useColor ? '\x1b[1m' : ''; +const DIM = useColor ? '\x1b[2m' : ''; +const RESET = useColor ? '\x1b[0m' : ''; + +// --- Ordered pass list (derived from pipeline.rs DebugLogEntry calls) --- +function derivePassOrder(): string[] { + const pipelinePath = path.join( + REPO_ROOT, + 'compiler/crates/react_compiler/src/entrypoint/pipeline.rs', + ); + const content = fs.readFileSync(pipelinePath, 'utf8'); + const matches = [...content.matchAll(/DebugLogEntry::new\("([^"]+)"/g)]; + return matches.map(m => m[1]); +} + +const PASS_ORDER = derivePassOrder(); + +// --- Detect last ported pass from pipeline.rs --- +function detectLastPortedPass(): string { + if (PASS_ORDER.length === 0) { + throw new Error('No ported passes found in pipeline.rs'); + } + return PASS_ORDER[PASS_ORDER.length - 1]; +} + +// --- Parse args --- +const [passArgRaw, fixturesPathArg] = positional; + +let passArg: string; +if (passArgRaw) { + passArg = passArgRaw; +} else { + passArg = detectLastPortedPass(); + if (!jsonMode && !failuresMode) { + console.log( + `No pass argument given, auto-detected last ported pass: ${BOLD}${passArg}${RESET}`, + ); + } +} +const DEFAULT_FIXTURES_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler', +); + +const fixturesPath = fixturesPathArg + ? path.resolve(fixturesPathArg) + : DEFAULT_FIXTURES_DIR; + +// --- Build native module --- +const NATIVE_DIR = path.join( + REPO_ROOT, + 'compiler/packages/babel-plugin-react-compiler-rust/native', +); +const NATIVE_NODE_PATH = path.join(NATIVE_DIR, 'index.node'); + +if (!jsonMode && !failuresMode) { + console.log('Building Rust native module...'); +} +try { + execSync('~/.cargo/bin/cargo build -p react_compiler_napi', { + cwd: path.join(REPO_ROOT, 'compiler/crates'), + stdio: + jsonMode || failuresMode ? ['inherit', 'pipe', 'inherit'] : 'inherit', + shell: true, + }); +} catch { + console.error(`${RED}ERROR: Failed to build Rust native module.${RESET}`); + process.exit(1); +} + +// Copy the built dylib as index.node (Node requires .node extension for native addons) +const TARGET_DIR = path.join(REPO_ROOT, 'compiler/target/debug'); +const dylib = fs.existsSync( + path.join(TARGET_DIR, 'libreact_compiler_napi.dylib'), +) + ? path.join(TARGET_DIR, 'libreact_compiler_napi.dylib') + : path.join(TARGET_DIR, 'libreact_compiler_napi.so'); + +if (!fs.existsSync(dylib)) { + console.error( + `${RED}ERROR: Could not find built native module in ${TARGET_DIR}${RESET}`, + ); + process.exit(1); +} +fs.copyFileSync(dylib, NATIVE_NODE_PATH); + +// --- Load plugins --- +const tsPlugin = require('../packages/babel-plugin-react-compiler/src').default; +const rustPlugin = + require('../packages/babel-plugin-react-compiler-rust/src').default; + +// --- Types --- +interface LogEntry { + kind: 'entry'; + name: string; + value: string; +} + +interface LogEvent { + kind: 'event'; + eventKind: string; + fnName: string | null; + detail: string; +} + +type LogItem = LogEntry | LogEvent; + +interface CompileOutput { + log: LogItem[]; + code: string | null; + error: string | null; +} + +type CompileMode = 'ts' | 'rust'; + +// --- Discover fixtures --- +function discoverFixtures(rootPath: string): string[] { + const stat = fs.statSync(rootPath); + if (stat.isFile()) { + return [rootPath]; + } + + const results: string[] = []; + function walk(dir: string): void { + for (const entry of fs.readdirSync(dir, {withFileTypes: true})) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walk(fullPath); + } else if ( + /\.(js|jsx|ts|tsx)$/.test(entry.name) && + !entry.name.endsWith('.expect.md') + ) { + results.push(fullPath); + } + } + } + walk(rootPath); + results.sort(); + return results; +} + +// --- Format a source location for comparison --- +function formatLoc(loc: unknown): string { + if (loc == null) return '(generated)'; + if (typeof loc === 'symbol') return '(generated)'; + const l = loc as Record; + const start = l.start as Record | undefined; + const end = l.end as Record | undefined; + if (start && end) { + return `${start.line}:${start.column}-${end.line}:${end.column}`; + } + return String(loc); +} + +// --- Compile a fixture through a Babel plugin and capture debug entries --- +function compileFixture(mode: CompileMode, fixturePath: string): CompileOutput { + const source = fs.readFileSync(fixturePath, 'utf8'); + const firstLine = source.substring(0, source.indexOf('\n')); + + // Parse pragma config + const pragmaOpts = parseConfigPragmaForTests(firstLine, { + compilationMode: 'all', + }); + + // Capture debug entries and logger events in order, stopping after the target pass + const log: LogItem[] = []; + let reachedTarget = false; + + const logger = { + logEvent(_filename: string | null, event: Record): void { + if (reachedTarget) return; + const kind = event.kind as string; + if ( + kind === 'CompileError' || + kind === 'CompileSkip' || + // Skip CompileUnexpectedThrow: this is a TS-only artifact logged when a pass + // throws instead of recording errors. The Rust port uses Result-based error + // propagation, so this event is never emitted and should be excluded from comparison. + // kind === 'CompileUnexpectedThrow' || + kind === 'PipelineError' + ) { + const fnName = (event.fnName as string | null) ?? null; + let detail: string; + if (kind === 'CompileError') { + const d = event.detail as Record | undefined; + if (d) { + const lines = [ + `reason: ${d.reason ?? '(none)'}`, + `severity: ${d.severity ?? '(none)'}`, + `category: ${d.category ?? '(none)'}`, + ]; + if (d.description) { + lines.push(`description: ${d.description}`); + } + // CompilerDiagnostic stores details in this.options.details (no getter), + // while Rust JSON has details as a direct field. Check both paths. + const opts = (d as Record).options as + | Record + | undefined; + const details = (opts?.details ?? d.details) as + | Array> + | undefined; + if (details && details.length > 0) { + for (const item of details) { + if (item.kind === 'error') { + lines.push( + ` error: ${formatLoc(item.loc)}${ + item.message ? ': ' + item.message : '' + }`, + ); + } else if (item.kind === 'hint') { + lines.push(` hint: ${item.message ?? ''}`); + } + } + } + // Legacy CompilerErrorDetail has loc directly + if (d.loc && !details) { + lines.push(`loc: ${formatLoc(d.loc)}`); + } + detail = lines.join('\n '); + } else { + detail = '(no detail)'; + } + } else if (kind === 'CompileSkip') { + detail = (event.reason as string) ?? '(no reason)'; + } else { + detail = (event.data as string) ?? '(no data)'; + } + log.push({kind: 'event', eventKind: kind, fnName, detail}); + } + }, + debugLogIRs(entry: CompilerPipelineValue): void { + if (reachedTarget) return; + if (entry.name === 'EnvironmentConfig') return; + if (entry.kind === 'hir') { + // TS pipeline emits HIR objects โ€” convert to debug string + log.push({ + kind: 'entry', + name: entry.name, + value: printDebugHIR(entry.value), + }); + } else if (entry.kind === 'debug') { + // Rust pipeline (and TS EnvironmentConfig) emits pre-formatted strings + log.push({ + kind: 'entry', + name: entry.name, + value: entry.value, + }); + } else if (entry.kind === 'reactive') { + log.push({ + kind: 'entry', + name: entry.name, + value: printDebugReactiveFunction(entry.value), + }); + } else if (entry.kind === 'ast' && entry.name === passArg) { + throw new Error( + `TODO: test-rust-port does not yet support '${entry.kind}' log entries ` + + `(pass "${entry.name}"). Extend the debugLogIRs handler to support this kind.`, + ); + } + if (entry.name === passArg) { + reachedTarget = true; + } + }, + }; + + // Determine parser plugins โ€” scan the leading comment block for pragmas + // since @flow is typically on line 3-4 inside a doc comment, not the first line. + const headerBlock = source.substring(0, source.indexOf('*/') + 2 || 200); + const isFlow = headerBlock.includes('@flow'); + const isScript = firstLine.includes('@script'); + + const plugin = mode === 'ts' ? tsPlugin : rustPlugin; + + const pluginOptions = { + ...pragmaOpts, + ...(compilationModeArg != null + ? {compilationMode: compilationModeArg} + : {}), + panicThreshold: 'all_errors' as const, + logger, + }; + + // For Flow files, use hermes-parser which supports component syntax. + // For TypeScript files, use @babel/parser with typescript+jsx plugins. + const babelPlugins: Array = isFlow + ? [hermesParserPlugin, [plugin, pluginOptions]] + : [[plugin, pluginOptions]]; + + let error: string | null = null; + let code: string | null = null; + try { + const result = babel.transformSync(source, { + filename: fixturePath, + sourceType: isScript ? 'script' : 'module', + ...(isFlow ? {} : {parserOpts: {plugins: ['typescript', 'jsx']}}), + plugins: babelPlugins, + configFile: false, + babelrc: false, + }); + code = result?.code ?? null; + } catch (e) { + error = e instanceof Error ? e.message : String(e); + } + + return {log, code, error}; +} + +// --- Format a single log item as comparable string --- +function formatLogItem(item: LogItem): string { + if (item.kind === 'entry') { + return `## ${item.name}\n${item.value}`; + } else { + return `[${item.eventKind}]${item.fnName ? ' ' + item.fnName : ''}: ${ + item.detail + }`; + } +} + +// --- Format log items as comparable string --- +function formatLog(log: LogItem[]): string { + return log.map(formatLogItem).join('\n'); +} + +// --- Normalize opaque IDs --- +// Type IDs and Identifier IDs are opaque identifiers whose absolute values +// differ between TS and Rust due to differences in allocation order. +// We normalize by remapping each unique ID to a sequential index. +function normalizeIds(text: string): string { + // ID maps are reset at function boundaries (## HIR) because TS uses a global + // type counter while Rust creates a fresh Environment per function, so raw IDs + // from different functions may collide in Rust but never in TS. + let typeMap = new Map(); + let nextTypeId = 0; + let idMap = new Map(); + let nextIdId = 0; + let declMap = new Map(); + let nextDeclId = 0; + let generatedMap = new Map(); + let nextGeneratedId = 0; + let blockMap = new Map(); + let nextBlockId = 0; + let isFirstHIR = true; + + // Process line-by-line so we can reset maps at function boundaries + const lines = text.split('\n'); + const result = lines.map(line => { + // Reset all maps when a new function's compilation starts (## HIR header). + // The first HIR entry doesn't need a reset since maps are already empty. + if (line === '## HIR') { + if (!isFirstHIR) { + typeMap = new Map(); + nextTypeId = 0; + idMap = new Map(); + nextIdId = 0; + declMap = new Map(); + nextDeclId = 0; + generatedMap = new Map(); + nextGeneratedId = 0; + blockMap = new Map(); + nextBlockId = 0; + } + isFirstHIR = false; + } + + return ( + line + // Normalize block IDs (bb0, bb1, ...) โ€” these are auto-incrementing counters + // that may differ between TS and Rust due to different block allocation counts + // in earlier passes (lowering, IIFE inlining, etc.). + .replace(/\bbb(\d+)\b/g, (_match, num) => { + const key = `bb:${num}`; + if (!blockMap.has(key)) { + blockMap.set(key, nextBlockId++); + } + return `bb${blockMap.get(key)}`; + }) + // Normalize shape IDs โ€” these are auto-incrementing counters + // that may differ between TS and Rust due to allocation ordering. + .replace(//g, (_match, num) => { + const key = `generated:${num}`; + if (!generatedMap.has(key)) { + generatedMap.set(key, nextGeneratedId++); + } + return ``; + }) + .replace(/Type\(\d+\)/g, match => { + if (!typeMap.has(match)) { + typeMap.set(match, nextTypeId++); + } + return `Type(${typeMap.get(match)})`; + }) + .replace(/((?:id|declarationId): )(\d+)/g, (_match, prefix, num) => { + if (prefix === 'id: ') { + const key = `id:${num}`; + if (!idMap.has(key)) { + idMap.set(key, nextIdId++); + } + return `${prefix}${idMap.get(key)}`; + } else { + const key = `decl:${num}`; + if (!declMap.has(key)) { + declMap.set(key, nextDeclId++); + } + return `${prefix}${declMap.get(key)}`; + } + }) + .replace(/Identifier\((\d+)\)/g, (_match, num) => { + const key = `id:${num}`; + if (!idMap.has(key)) { + idMap.set(key, nextIdId++); + } + return `Identifier(${idMap.get(key)})`; + }) + // Normalize printed identifiers like "x$5" in error descriptions. + // The $N suffix is an opaque IdentifierId that may differ between TS and Rust. + .replace(/(\w+)\$(\d+)/g, (_match, name, num) => { + const key = `id:${num}`; + if (!idMap.has(key)) { + idMap.set(key, nextIdId++); + } + return `${name}\$${idMap.get(key)}`; + }) + // Normalize mutableRange: [N:M] values by stripping them entirely. + // In TS, identifier.mutableRange shares a reference with scope.range, + // so modifications to scope.range automatically propagate. In Rust, + // mutableRange is a copy and diverges from scope.range after certain + // passes. Since scope.range is separately displayed and validated, + // mutableRange comparison adds noise without catching real bugs. + .replace(/mutableRange: \[\d+:\d+\]/g, 'mutableRange: [_:_]') + ); + }); + return result.join('\n'); +} + +// --- Simple unified diff --- +function unifiedDiff(expected: string, actual: string): string { + const expectedLines = expected.split('\n'); + const actualLines = actual.split('\n'); + const lines: string[] = []; + lines.push(`${RED}--- TypeScript${RESET}`); + lines.push(`${GREEN}+++ Rust${RESET}`); + + // Simple line-by-line diff (not a real unified diff, but good enough for debugging) + const maxLen = Math.max(expectedLines.length, actualLines.length); + let contextStart = -1; + for (let i = 0; i < maxLen; i++) { + const eLine = i < expectedLines.length ? expectedLines[i] : undefined; + const aLine = i < actualLines.length ? actualLines[i] : undefined; + if (eLine === aLine) { + // matching line โ€” skip (or show as context near diffs) + continue; + } + if (contextStart !== i) { + lines.push(`${YELLOW}@@ line ${i + 1} @@${RESET}`); + } + contextStart = i + 1; + if (eLine !== undefined && aLine !== undefined) { + lines.push(`${RED}-${eLine}${RESET}`); + lines.push(`${GREEN}+${aLine}${RESET}`); + } else if (eLine !== undefined) { + lines.push(`${RED}-${eLine}${RESET}`); + } else if (aLine !== undefined) { + lines.push(`${GREEN}+${aLine}${RESET}`); + } + } + return lines.join('\n'); +} + +// --- Format code with prettier --- +async function formatCode(code: string, isFlow: boolean): Promise { + return prettier.format(code, { + semi: true, + parser: isFlow ? 'flow' : 'babel-ts', + }); +} + +// --- Main --- +const fixtures = discoverFixtures(fixturesPath); +if (fixtures.length === 0) { + console.error('No fixtures found at', fixturesPath); + process.exit(1); +} + +if (!jsonMode && !failuresMode) { + console.log( + `Testing ${BOLD}${fixtures.length}${RESET} fixtures for pass: ${BOLD}${passArg}${RESET}`, + ); + console.log(''); +} + +let passed = 0; +let failed = 0; +let tsHadEntries = false; +const failures: Array<{ + fixture: string; + detail: string; +}> = []; +const failedFixtures: string[] = []; + +// Code comparison tracking +let codePassed = 0; +let codeFailed = 0; +const codeFailures: Array<{ + fixture: string; + detail: string; +}> = []; +const codeFailedFixtures: string[] = []; + +// Per-pass failure tracking for frontier detection +const perPassResults = new Map(); +for (const pass of PASS_ORDER) { + perPassResults.set(pass, {passed: 0, failed: 0}); +} + +// --- Find the earliest diverging pass for a fixture --- +function findDivergencePass(tsLog: LogItem[], rustLog: LogItem[]): string { + const maxLen = Math.max(tsLog.length, rustLog.length); + for (let i = 0; i < maxLen; i++) { + const tsItem = i < tsLog.length ? tsLog[i] : undefined; + const rustItem = i < rustLog.length ? rustLog[i] : undefined; + + if (tsItem === undefined || rustItem === undefined) { + // One log is shorter โ€” attribute to the pass of the last available entry + const item = tsItem ?? rustItem; + if (item && item.kind === 'entry') { + return item.name; + } + // For events, attribute to the preceding entry's pass + for (let j = i - 1; j >= 0; j--) { + const prev = tsLog[j] ?? rustLog[j]; + if (prev && prev.kind === 'entry') return prev.name; + } + // No preceding entry โ€” attribute to first pass + return PASS_ORDER[0]; + } + + const tsFormatted = normalizeIds(formatLogItem(tsItem)); + const rustFormatted = normalizeIds(formatLogItem(rustItem)); + if (tsFormatted !== rustFormatted) { + if (tsItem.kind === 'entry') { + return tsItem.name; + } + // For events, find the most recent entry pass + for (let j = i - 1; j >= 0; j--) { + if (tsLog[j] && tsLog[j].kind === 'entry') { + return (tsLog[j] as LogEntry).name; + } + } + // No preceding entry โ€” attribute to first pass + return PASS_ORDER[0]; + } + } + // No divergence found (shouldn't happen since caller verified logs differ) + return PASS_ORDER[0]; +} + +(async () => { + for (const fixturePath of fixtures) { + const relPath = path.relative(REPO_ROOT, fixturePath); + const ts = compileFixture('ts', fixturePath); + const rust = compileFixture('rust', fixturePath); + + // Check if TS produced any entries for the target pass + if (ts.log.some(item => item.kind === 'entry' && item.name === passArg)) { + tsHadEntries = true; + } + + // Compare the full log (entries + events in order, up to target pass) + const tsFormatted = normalizeIds(formatLog(ts.log)); + const rustFormatted = normalizeIds(formatLog(rust.log)); + + // When both compilers throw an error (same final outcome), tolerate + // differences in debug output. Rust's fault-tolerant pipeline emits + // partial debug IR before reaching the same fatal error that TS's + // throw-immediate approach reports with no debug output at all. + const bothErrored = + ts.error != null && + rust.error != null && + ts.code == null && + rust.code == null; + + if (tsFormatted === rustFormatted || bothErrored) { + passed++; + // Count as passed for all passes that appeared in the log + const seenPasses = new Set(); + for (const item of ts.log) { + if (item.kind === 'entry') seenPasses.add(item.name); + } + for (const pass of seenPasses) { + const stats = perPassResults.get(pass); + if (stats) stats.passed++; + } + } else { + failed++; + // Find which pass diverged and attribute the failure + const divergePass = findDivergencePass(ts.log, rust.log); + const stats = perPassResults.get(divergePass); + if (stats) stats.failed++; + // Count passes before divergence as passed + const seenPasses: string[] = []; + for (const item of ts.log) { + if (item.kind === 'entry' && item.name !== divergePass) { + seenPasses.push(item.name); + } else if (item.kind === 'entry') { + break; + } + } + for (const pass of seenPasses) { + const stats = perPassResults.get(pass); + if (stats) stats.passed++; + } + + failedFixtures.push(relPath); + if (limitArg === 0 || failures.length < limitArg) { + failures.push({ + fixture: relPath, + detail: unifiedDiff(tsFormatted, rustFormatted), + }); + } + } + + // Compare final code output + const source = fs.readFileSync(fixturePath, 'utf8'); + const headerBlock = source.substring(0, source.indexOf('*/') + 2 || 200); + const isFlow = headerBlock.includes('@flow'); + try { + const tsCode = await formatCode(ts.code ?? '', isFlow); + const rustCode = await formatCode(rust.code ?? '', isFlow); + if (tsCode === rustCode) { + codePassed++; + } else { + codeFailed++; + codeFailedFixtures.push(relPath); + if (limitArg === 0 || codeFailures.length < limitArg) { + codeFailures.push({ + fixture: relPath, + detail: unifiedDiff(tsCode, rustCode), + }); + } + } + } catch { + // If prettier fails, treat as a code mismatch + const tsCode = ts.code ?? ''; + const rustCode = rust.code ?? ''; + if (tsCode === rustCode) { + codePassed++; + } else { + codeFailed++; + codeFailedFixtures.push(relPath); + if (limitArg === 0 || codeFailures.length < limitArg) { + codeFailures.push({ + fixture: relPath, + detail: unifiedDiff(tsCode, rustCode), + }); + } + } + } + } + + // --- Check for invalid pass name --- + if (!tsHadEntries) { + console.error( + `${RED}ERROR: TypeScript compiler produced no log entries for pass "${passArg}" across all fixtures.${RESET}`, + ); + console.error('This likely means the pass name is incorrect.'); + console.error(''); + console.error( + 'Pass names must match exactly as used in Pipeline.ts, e.g.:', + ); + console.error( + ' HIR, PruneMaybeThrows, SSA, InferTypes, AnalyseFunctions, ...', + ); + process.exit(1); + } + + // --- Compute frontier --- + let frontier: string | null = null; + for (const pass of PASS_ORDER) { + const stats = perPassResults.get(pass); + if (stats && stats.failed > 0) { + frontier = pass; + break; + } + } + + // --- Summary --- + const total = fixtures.length; + let frontierStr: string; + if (frontier != null) { + frontierStr = frontier; + } else if (passArgRaw) { + // Explicit pass arg given and it's clean โ€” we can't know the global frontier + frontierStr = `${passArg} passes, rerun without a pass name to find frontier`; + } else { + frontierStr = 'none'; + } + + // --- Per-pass breakdown --- + const perPassParts: string[] = []; + for (const pass of PASS_ORDER) { + const stats = perPassResults.get(pass); + if (stats && (stats.passed > 0 || stats.failed > 0)) { + perPassParts.push( + `${pass} ${stats.passed}/${stats.passed + stats.failed}`, + ); + } + } + + // --- Output --- + if (jsonMode) { + const output = { + pass: passArg, + autoDetected: !passArgRaw, + total, + passed, + failed, + frontier: frontier, + perPass: Object.fromEntries( + [...perPassResults.entries()].filter( + ([_, v]) => v.passed > 0 || v.failed > 0, + ), + ), + failures: failedFixtures, + codePassed, + codeFailed, + codeFailures: codeFailedFixtures, + }; + console.log(JSON.stringify(output)); + } else if (failuresMode) { + for (const f of failedFixtures) { + console.log(f); + } + } else { + const summaryColor = failed === 0 ? GREEN : RED; + const summaryLine = `${summaryColor}Results: ${passed} passed, ${failed} failed (${total} total), frontier: ${frontierStr}${RESET}`; + const codeSummaryColor = codeFailed === 0 ? GREEN : RED; + const codeSummaryLine = `${codeSummaryColor}Code: ${codePassed} passed, ${codeFailed} failed (${total} total)${RESET}`; + + // Print summary first + console.log(summaryLine); + console.log(codeSummaryLine); + if (perPassParts.length > 0) { + console.log(`Per-pass: ${perPassParts.join(', ')}`); + } + console.log(''); + + // --- Show log failures --- + for (const failure of failures) { + console.log(`${RED}FAIL${RESET} ${failure.fixture}`); + console.log(failure.detail); + console.log(''); + } + + // --- Show code failures --- + if (codeFailures.length > 0) { + console.log(`${BOLD}--- Code comparison failures ---${RESET}`); + console.log(''); + for (const failure of codeFailures) { + console.log(`${RED}FAIL (code)${RESET} ${failure.fixture}`); + console.log(failure.detail); + console.log(''); + } + } + + // --- Summary again (so tail -1 works) --- + console.log('---'); + if (failures.length < failed) { + console.log( + `${DIM} (showing first ${failures.length} of ${failed} log failures)${RESET}`, + ); + } + if (codeFailures.length < codeFailed) { + console.log( + `${DIM} (showing first ${codeFailures.length} of ${codeFailed} code failures)${RESET}`, + ); + } + console.log(summaryLine); + console.log(codeSummaryLine); + } + + process.exit(failed > 0 || codeFailed > 0 ? 1 : 0); +})(); diff --git a/compiler/scripts/ts-compile-fixture.ts b/compiler/scripts/ts-compile-fixture.ts new file mode 100644 index 000000000000..1ad81ad425c0 --- /dev/null +++ b/compiler/scripts/ts-compile-fixture.ts @@ -0,0 +1,697 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * TS test binary for the Rust port testing infrastructure. + * + * Implements the compiler pipeline independently (NOT using compile() or + * runWithEnvironment()), calling each pass function directly in the same + * sequence as the Rust binary. This ensures both sides have exactly matching + * behavior. + * + * Takes a compiler pass name and a fixture path, finds every top-level + * function, runs the pipeline up to the target pass for each, and prints + * a detailed debug representation to stdout. + * + * Usage: npx tsx compiler/scripts/ts-compile-fixture.mjs + */ + +import {parse} from '@babel/parser'; +import _traverse from '@babel/traverse'; +const traverse: typeof _traverse = (_traverse as any).default || _traverse; +import * as t from '@babel/types'; +import {type NodePath} from '@babel/traverse'; +import fs from 'fs'; +import path from 'path'; + +// --- Import pass functions directly from compiler source --- +import {lower} from '../packages/babel-plugin-react-compiler/src/HIR/BuildHIR'; +import { + Environment, + type EnvironmentConfig, + type ReactFunctionType, +} from '../packages/babel-plugin-react-compiler/src/HIR/Environment'; +import {findContextIdentifiers} from '../packages/babel-plugin-react-compiler/src/HIR/FindContextIdentifiers'; +import {mergeConsecutiveBlocks} from '../packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks'; +import { + assertConsistentIdentifiers, + assertTerminalSuccessorsExist, + assertTerminalPredsExist, +} from '../packages/babel-plugin-react-compiler/src/HIR'; +import {assertValidBlockNesting} from '../packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting'; +import {assertValidMutableRanges} from '../packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges'; +import {pruneUnusedLabelsHIR} from '../packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR'; +import {mergeOverlappingReactiveScopesHIR} from '../packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR'; +import {buildReactiveScopeTerminalsHIR} from '../packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR'; +import {alignReactiveScopesToBlockScopesHIR} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR'; +import {flattenReactiveLoopsHIR} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenReactiveLoopsHIR'; +import {flattenScopesWithHooksOrUseHIR} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR'; +import {propagateScopeDependenciesHIR} from '../packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR'; + +import { + pruneMaybeThrows, + constantPropagation, + deadCodeElimination, +} from '../packages/babel-plugin-react-compiler/src/Optimization'; +import {optimizePropsMethodCalls} from '../packages/babel-plugin-react-compiler/src/Optimization/OptimizePropsMethodCalls'; +import {outlineFunctions} from '../packages/babel-plugin-react-compiler/src/Optimization/OutlineFunctions'; +import {optimizeForSSR} from '../packages/babel-plugin-react-compiler/src/Optimization/OptimizeForSSR'; + +import { + enterSSA, + eliminateRedundantPhi, + rewriteInstructionKindsBasedOnReassignment, +} from '../packages/babel-plugin-react-compiler/src/SSA'; +import {inferTypes} from '../packages/babel-plugin-react-compiler/src/TypeInference'; + +import { + analyseFunctions, + dropManualMemoization, + inferReactivePlaces, + inlineImmediatelyInvokedFunctionExpressions, +} from '../packages/babel-plugin-react-compiler/src/Inference'; +import {inferMutationAliasingEffects} from '../packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects'; +import {inferMutationAliasingRanges} from '../packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingRanges'; + +import { + buildReactiveFunction, + inferReactiveScopeVariables, + memoizeFbtAndMacroOperandsInSameScope, + promoteUsedTemporaries, + propagateEarlyReturns, + pruneHoistedContexts, + pruneNonEscapingScopes, + pruneNonReactiveDependencies, + pruneUnusedLValues, + pruneUnusedLabels, + pruneUnusedScopes, + mergeReactiveScopesThatInvalidateTogether, + renameVariables, + extractScopeDeclarationsFromDestructuring, + codegenFunction, + alignObjectMethodScopes, +} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes'; +import {alignMethodCallScopes} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignMethodCallScopes'; +import {pruneAlwaysInvalidatingScopes} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneAlwaysInvalidatingScopes'; +import {stabilizeBlockIds} from '../packages/babel-plugin-react-compiler/src/ReactiveScopes/StabilizeBlockIds'; + +import {nameAnonymousFunctions} from '../packages/babel-plugin-react-compiler/src/Transform/NameAnonymousFunctions'; + +import { + validateContextVariableLValues, + validateHooksUsage, + validateNoCapitalizedCalls, + validateNoRefAccessInRender, + validateNoSetStateInRender, + validatePreservedManualMemoization, + validateUseMemo, +} from '../packages/babel-plugin-react-compiler/src/Validation'; +import {validateLocalsNotReassignedAfterRender} from '../packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender'; +import {validateNoFreezingKnownMutableFunctions} from '../packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions'; + +import {CompilerError} from '../packages/babel-plugin-react-compiler/src/CompilerError'; +import {type HIRFunction} from '../packages/babel-plugin-react-compiler/src/HIR/HIR'; + +import {parseConfigPragmaForTests} from '../packages/babel-plugin-react-compiler/src/Utils/TestUtils'; +import { + parsePluginOptions, + ProgramContext, +} from '../packages/babel-plugin-react-compiler/src/Entrypoint'; + +import {debugPrintHIR} from './debug-print-hir.mjs'; +import {debugPrintReactive} from './debug-print-reactive.mjs'; +import {debugPrintError} from './debug-print-error.mjs'; + +// --- Arguments --- +const [passArg, fixturePath] = process.argv.slice(2); + +if (!passArg || !fixturePath) { + console.error( + 'Usage: npx tsx compiler/scripts/ts-compile-fixture.mjs ', + ); + process.exit(1); +} + +// --- Valid pass names (checkpoint names) --- +const VALID_PASSES = new Set([ + 'HIR', + 'PruneMaybeThrows', + 'DropManualMemoization', + 'InlineIIFEs', + 'MergeConsecutiveBlocks', + 'SSA', + 'EliminateRedundantPhi', + 'ConstantPropagation', + 'InferTypes', + 'OptimizePropsMethodCalls', + 'AnalyseFunctions', + 'InferMutationAliasingEffects', + 'OptimizeForSSR', + 'DeadCodeElimination', + 'PruneMaybeThrows2', + 'InferMutationAliasingRanges', + 'InferReactivePlaces', + 'RewriteInstructionKinds', + 'InferReactiveScopeVariables', + 'MemoizeFbtOperands', + 'NameAnonymousFunctions', + 'OutlineFunctions', + 'AlignMethodCallScopes', + 'AlignObjectMethodScopes', + 'PruneUnusedLabelsHIR', + 'AlignReactiveScopesToBlockScopes', + 'MergeOverlappingReactiveScopes', + 'BuildReactiveScopeTerminals', + 'FlattenReactiveLoops', + 'FlattenScopesWithHooksOrUse', + 'PropagateScopeDependencies', + 'BuildReactiveFunction', + 'PruneUnusedLabels', + 'PruneNonEscapingScopes', + 'PruneNonReactiveDependencies', + 'PruneUnusedScopes', + 'MergeReactiveScopesThatInvalidateTogether', + 'PruneAlwaysInvalidatingScopes', + 'PropagateEarlyReturns', + 'PruneUnusedLValues', + 'PromoteUsedTemporaries', + 'ExtractScopeDeclarationsFromDestructuring', + 'StabilizeBlockIds', + 'RenameVariables', + 'PruneHoistedContexts', + 'Codegen', +]); + +if (!VALID_PASSES.has(passArg)) { + console.error(`Unknown pass: ${passArg}`); + console.error(`Valid passes: ${[...VALID_PASSES].join(', ')}`); + process.exit(1); +} + +// --- Read fixture source --- +const source = fs.readFileSync(fixturePath, 'utf8'); +const firstLine = source.substring(0, source.indexOf('\n')); + +// Determine language and source type +const language = firstLine.includes('@flow') ? 'flow' : 'typescript'; +const sourceType = firstLine.includes('@script') ? 'script' : 'module'; + +// --- Parse config pragmas --- +const parsedOpts = parseConfigPragmaForTests(firstLine, { + compilationMode: 'all', +}); +const envConfig: EnvironmentConfig = { + ...parsedOpts.environment, + assertValidMutableRanges: true, +}; + +// --- Parse the fixture --- +const plugins: Array = + language === 'flow' ? ['flow', 'jsx'] : ['typescript', 'jsx']; +const inputAst = parse(source, { + sourceFilename: path.basename(fixturePath), + plugins, + sourceType, + errorRecovery: true, +}); + +// --- Find ALL top-level functions --- +const functionPaths: Array< + NodePath< + t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression + > +> = []; +let programPath: NodePath | null = null; + +traverse(inputAst, { + Program(nodePath: NodePath) { + programPath = nodePath; + }, + 'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression'( + nodePath: NodePath< + t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression + >, + ) { + if (isTopLevelFunction(nodePath)) { + functionPaths.push(nodePath); + nodePath.skip(); + } + }, + ClassDeclaration(nodePath: NodePath) { + nodePath.skip(); + }, + ClassExpression(nodePath: NodePath) { + nodePath.skip(); + }, +}); + +function isTopLevelFunction(fnPath: NodePath): boolean { + let current = fnPath; + while (current.parentPath) { + const parent = current.parentPath; + if (parent.isProgram()) { + return true; + } + if (parent.isVariableDeclarator()) { + current = parent; + continue; + } + if (parent.isVariableDeclaration()) { + current = parent; + continue; + } + if ( + parent.isExportNamedDeclaration() || + parent.isExportDefaultDeclaration() + ) { + current = parent; + continue; + } + return false; + } + return false; +} + +if (functionPaths.length === 0) { + console.error('No top-level functions found in fixture'); + process.exit(1); +} + +// --- Compile each function --- +const filename = '/' + path.basename(fixturePath); +const allOutputs: string[] = []; + +for (const fnPath of functionPaths) { + const output = compileOneFunction(fnPath); + if (output != null) { + allOutputs.push(output); + } +} + +// --- Write output --- +if (allOutputs.length === 0) { + console.error('No functions produced output'); + process.exit(1); +} +const finalOutput = allOutputs.join('\n---\n'); +process.stdout.write(finalOutput); +if (!finalOutput.endsWith('\n')) { + process.stdout.write('\n'); +} + +// --- Run the pipeline for a single function, mirroring Rust's run_pipeline --- +function compileOneFunction( + fnPath: NodePath< + t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression + >, +): string | null { + const contextIdentifiers = findContextIdentifiers(fnPath); + const env = new Environment( + fnPath.scope, + 'Other' as ReactFunctionType, + 'client', // outputMode + envConfig, + contextIdentifiers, + fnPath, + null, // logger + filename, + source, + new ProgramContext({ + program: programPath!, + opts: parsedOpts, + filename, + code: source, + suppressions: [], + hasModuleScopeOptOut: false, + }), + ); + + const pass = passArg; + + function formatEnvErrors(): string { + return debugPrintError(env.aggregateErrors()); + } + + function printHIR(hir: HIRFunction): string { + return debugPrintHIR(null, hir); + } + + function checkpointHIR(hir: HIRFunction): string { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return printHIR(hir); + } + + try { + // --- HIR Phase --- + const hir = lower(fnPath, env); + if (pass === 'HIR') { + return checkpointHIR(hir); + } + + pruneMaybeThrows(hir); + if (pass === 'PruneMaybeThrows') { + return checkpointHIR(hir); + } + + validateContextVariableLValues(hir); + validateUseMemo(hir); + + if (env.enableDropManualMemoization) { + dropManualMemoization(hir); + } + if (pass === 'DropManualMemoization') { + return checkpointHIR(hir); + } + + inlineImmediatelyInvokedFunctionExpressions(hir); + if (pass === 'InlineIIFEs') { + return checkpointHIR(hir); + } + + mergeConsecutiveBlocks(hir); + if (pass === 'MergeConsecutiveBlocks') { + return checkpointHIR(hir); + } + + assertConsistentIdentifiers(hir); + assertTerminalSuccessorsExist(hir); + + enterSSA(hir); + if (pass === 'SSA') { + return checkpointHIR(hir); + } + + eliminateRedundantPhi(hir); + if (pass === 'EliminateRedundantPhi') { + return checkpointHIR(hir); + } + + assertConsistentIdentifiers(hir); + + constantPropagation(hir); + if (pass === 'ConstantPropagation') { + return checkpointHIR(hir); + } + + inferTypes(hir); + if (pass === 'InferTypes') { + return checkpointHIR(hir); + } + + if (env.enableValidations) { + if (env.config.validateHooksUsage) { + validateHooksUsage(hir); + } + if (env.config.validateNoCapitalizedCalls) { + validateNoCapitalizedCalls(hir); + } + } + + optimizePropsMethodCalls(hir); + if (pass === 'OptimizePropsMethodCalls') { + return checkpointHIR(hir); + } + + analyseFunctions(hir); + if (pass === 'AnalyseFunctions') { + return checkpointHIR(hir); + } + + inferMutationAliasingEffects(hir); + if (pass === 'InferMutationAliasingEffects') { + return checkpointHIR(hir); + } + + if (env.outputMode === 'ssr') { + optimizeForSSR(hir); + } + if (pass === 'OptimizeForSSR') { + return checkpointHIR(hir); + } + + deadCodeElimination(hir); + if (pass === 'DeadCodeElimination') { + return checkpointHIR(hir); + } + + pruneMaybeThrows(hir); + if (pass === 'PruneMaybeThrows2') { + return checkpointHIR(hir); + } + + inferMutationAliasingRanges(hir, {isFunctionExpression: false}); + if (pass === 'InferMutationAliasingRanges') { + return checkpointHIR(hir); + } + + if (env.enableValidations) { + validateLocalsNotReassignedAfterRender(hir); + + if (env.config.assertValidMutableRanges) { + assertValidMutableRanges(hir); + } + + if (env.config.validateRefAccessDuringRender) { + validateNoRefAccessInRender(hir); + } + + if (env.config.validateNoSetStateInRender) { + validateNoSetStateInRender(hir); + } + + validateNoFreezingKnownMutableFunctions(hir); + } + + inferReactivePlaces(hir); + if (pass === 'InferReactivePlaces') { + return checkpointHIR(hir); + } + + rewriteInstructionKindsBasedOnReassignment(hir); + if (pass === 'RewriteInstructionKinds') { + return checkpointHIR(hir); + } + + if (env.enableMemoization) { + inferReactiveScopeVariables(hir); + } + if (pass === 'InferReactiveScopeVariables') { + return checkpointHIR(hir); + } + + const fbtOperands = memoizeFbtAndMacroOperandsInSameScope(hir); + if (pass === 'MemoizeFbtOperands') { + return checkpointHIR(hir); + } + + if (env.config.enableNameAnonymousFunctions) { + nameAnonymousFunctions(hir); + } + if (pass === 'NameAnonymousFunctions') { + return checkpointHIR(hir); + } + + if (env.config.enableFunctionOutlining) { + outlineFunctions(hir, fbtOperands); + } + if (pass === 'OutlineFunctions') { + return checkpointHIR(hir); + } + + alignMethodCallScopes(hir); + if (pass === 'AlignMethodCallScopes') { + return checkpointHIR(hir); + } + + alignObjectMethodScopes(hir); + if (pass === 'AlignObjectMethodScopes') { + return checkpointHIR(hir); + } + + pruneUnusedLabelsHIR(hir); + if (pass === 'PruneUnusedLabelsHIR') { + return checkpointHIR(hir); + } + + alignReactiveScopesToBlockScopesHIR(hir); + if (pass === 'AlignReactiveScopesToBlockScopes') { + return checkpointHIR(hir); + } + + mergeOverlappingReactiveScopesHIR(hir); + if (pass === 'MergeOverlappingReactiveScopes') { + return checkpointHIR(hir); + } + + assertValidBlockNesting(hir); + + buildReactiveScopeTerminalsHIR(hir); + if (pass === 'BuildReactiveScopeTerminals') { + return checkpointHIR(hir); + } + + assertValidBlockNesting(hir); + + flattenReactiveLoopsHIR(hir); + if (pass === 'FlattenReactiveLoops') { + return checkpointHIR(hir); + } + + flattenScopesWithHooksOrUseHIR(hir); + if (pass === 'FlattenScopesWithHooksOrUse') { + return checkpointHIR(hir); + } + + assertTerminalSuccessorsExist(hir); + assertTerminalPredsExist(hir); + + propagateScopeDependenciesHIR(hir); + if (pass === 'PropagateScopeDependencies') { + return checkpointHIR(hir); + } + + // --- Reactive Phase --- + const reactiveFunction = buildReactiveFunction(hir); + if (pass === 'BuildReactiveFunction') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneUnusedLabels(reactiveFunction); + if (pass === 'PruneUnusedLabels') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneNonEscapingScopes(reactiveFunction); + if (pass === 'PruneNonEscapingScopes') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneNonReactiveDependencies(reactiveFunction); + if (pass === 'PruneNonReactiveDependencies') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneUnusedScopes(reactiveFunction); + if (pass === 'PruneUnusedScopes') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + mergeReactiveScopesThatInvalidateTogether(reactiveFunction); + if (pass === 'MergeReactiveScopesThatInvalidateTogether') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneAlwaysInvalidatingScopes(reactiveFunction); + if (pass === 'PruneAlwaysInvalidatingScopes') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + propagateEarlyReturns(reactiveFunction); + if (pass === 'PropagateEarlyReturns') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneUnusedLValues(reactiveFunction); + if (pass === 'PruneUnusedLValues') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + promoteUsedTemporaries(reactiveFunction); + if (pass === 'PromoteUsedTemporaries') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + extractScopeDeclarationsFromDestructuring(reactiveFunction); + if (pass === 'ExtractScopeDeclarationsFromDestructuring') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + stabilizeBlockIds(reactiveFunction); + if (pass === 'StabilizeBlockIds') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + const uniqueIdentifiers = renameVariables(reactiveFunction); + if (pass === 'RenameVariables') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + pruneHoistedContexts(reactiveFunction); + if (pass === 'PruneHoistedContexts') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return debugPrintReactive(null, reactiveFunction); + } + + if ( + env.config.enablePreserveExistingMemoizationGuarantees || + env.config.validatePreserveExistingMemoizationGuarantees + ) { + validatePreservedManualMemoization(reactiveFunction); + } + + const ast = codegenFunction(reactiveFunction, { + uniqueIdentifiers, + fbtOperands, + }); + if (pass === 'Codegen') { + if (env.hasErrors()) { + return formatEnvErrors(); + } + return '(codegen ast)'; + } + + return null; + } catch (e) { + if (e instanceof CompilerError) { + return debugPrintError(e); + } + throw e; + } +} diff --git a/compiler/scripts/update-commit-message.js b/compiler/scripts/update-commit-message.js new file mode 100644 index 000000000000..7cda9547eccd --- /dev/null +++ b/compiler/scripts/update-commit-message.js @@ -0,0 +1,147 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * INSTALLATION: + * - `$ npm install octokit + * - Get a token from https://github.com/settings/tokens for use in the command below, + * set the token value as the GITHUB_AUTH_TOKEN environment variable + * + * USAGE: + * - $ GITHUB_AUTH_TOKEN="..." git filter-branch -f --msg-filter "node update-commit-message.js" 2364096862b72cf4d801ef2008c54252335a2df9..HEAD + */ + +const {Octokit, App} = require('octokit'); +const fs = require('fs'); + +const OWNER = 'facebook'; +const REPO = 'react-forget'; +const octokit = new Octokit({auth: process.env.GITHUB_AUTH_TOKEN}); + +const fetchPullRequest = async pullNumber => { + const response = await octokit.request( + 'GET /repos/{owner}/{repo}/pulls/{pull_number}', + { + owner: OWNER, + repo: REPO, + pull_number: pullNumber, + headers: { + 'X-GitHub-Api-Version': '2022-11-28', + }, + } + ); + return {body: response.data.body, title: response.data.title}; +}; + +function formatCommitMessage(str) { + let formattedStr = ''; + let line = ''; + + const trim = str.replace(/(\r\n|\n|\r)/gm, ' ').trim(); + if (!trim) { + return ''; + } + + // Split the string into words + const words = trim.split(' '); + // Iterate over each word + for (let i = 0; i < words.length; i++) { + // If adding the next word doesn't exceed the line length limit, add it to the line + if ((line + words[i]).length <= 80) { + line += words[i] + ' '; + } else { + // Otherwise, add the line to the formatted string and start a new line + formattedStr += line + '\n'; + line = words[i] + ' '; + } + } + // Add the last line to the formatted string + formattedStr += line; + return formattedStr; +} + +function filterMsg(response) { + const {body, title} = response; + + const msgs = body.split('\n\n').flatMap(x => x.split('\r\n')); + + const newMessage = []; + + // Add title + msgs.unshift(title); + + for (const msg of msgs) { + // remove "Stack from [ghstack] blurb" + if (msg.startsWith('Stack from ')) { + continue; + } + + // remove "* #1234" + if (msg.startsWith('* #')) { + continue; + } + + // remove "* __->__ #1234" + if (msg.startsWith('* __')) { + continue; + } + + const formattedStr = formatCommitMessage(msg); + if (!formattedStr) { + continue; + } + newMessage.push(formattedStr); + } + + const updatedMsg = newMessage.join('\n\n'); + return updatedMsg; +} + +function parsePullRequestNumber(text) { + if (!text) { + return null; + } + const ghstackUrlRegex = + /https:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/(\d+)/; + const ghstackMatch = text.match(ghstackUrlRegex); + if (ghstackMatch) { + return ghstackMatch[1]; + } + const firstLine = text.split('\n').filter(text => text.trim().length > 0)[0]; + if (firstLine == null) { + return null; + } + const prNumberRegex = /\(#(\d{3,})\)\s*$/; + const prNumberMatch = firstLine.match(prNumberRegex); + if (prNumberMatch) { + return prNumberMatch[1]; + } + return null; +} + +async function main() { + const data = fs.readFileSync(0, 'utf-8'); + const pr = parsePullRequestNumber(data); + + if (pr) { + try { + const response = await fetchPullRequest(pr); + if (!response.body) { + console.log(data); + return; + } + const newMessage = filterMsg(response); + console.log(newMessage); + return; + } catch (e) { + console.log(data); + return; + } + } + + console.log(data); +} + +main(); diff --git a/compiler/yarn.lock b/compiler/yarn.lock new file mode 100644 index 000000000000..a78afe242ee5 --- /dev/null +++ b/compiler/yarn.lock @@ -0,0 +1,11602 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@algolia/client-abtesting@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.23.4.tgz" + integrity sha512-WIMT2Kxy+FFWXWQxIU8QgbTioL+SGE24zhpj0kipG4uQbzXwONaWt7ffaYLjfge3gcGSgJVv+1VlahVckafluQ== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/client-analytics@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.23.4.tgz" + integrity sha512-4B9gChENsQA9kFmFlb+x3YhBz2Gx3vSsm81FHI1yJ3fn2zlxREHmfrjyqYoMunsU7BybT/o5Nb7ccCbm/vfseA== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/client-common@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.23.4.tgz" + integrity sha512-bsj0lwU2ytiWLtl7sPunr+oLe+0YJql9FozJln5BnIiqfKOaseSDdV42060vUy+D4373f2XBI009K/rm2IXYMA== + +"@algolia/client-insights@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.23.4.tgz" + integrity sha512-XSCtAYvJ/hnfDHfRVMbBH0dayR+2ofVZy3jf5qyifjguC6rwxDsSdQvXpT0QFVyG+h8UPGtDhMPoUIng4wIcZA== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/client-personalization@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.23.4.tgz" + integrity sha512-l/0QvqgRFFOf7BnKSJ3myd1WbDr86ftVaa3PQwlsNh7IpIHmvVcT83Bi5zlORozVGMwaKfyPZo6O48PZELsOeA== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/client-query-suggestions@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.23.4.tgz" + integrity sha512-TB0htrDgVacVGtPDyENoM6VIeYqR+pMsDovW94dfi2JoaRxfqu/tYmLpvgWcOknP6wLbr8bA+G7t/NiGksNAwQ== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/client-search@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.23.4.tgz" + integrity sha512-uBGo6KwUP6z+u6HZWRui8UJClS7fgUIAiYd1prUqCbkzDiCngTOzxaJbEvrdkK0hGCQtnPDiuNhC5MhtVNN4Eg== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/ingestion@1.23.4": + version "1.23.4" + resolved "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.23.4.tgz" + integrity sha512-Si6rFuGnSeEUPU9QchYvbknvEIyCRK7nkeaPVQdZpABU7m4V/tsiWdHmjVodtx3h20VZivJdHeQO9XbHxBOcCw== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/monitoring@1.23.4": + version "1.23.4" + resolved "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.23.4.tgz" + integrity sha512-EXGoVVTshraqPJgr5cMd1fq7Jm71Ew6MpGCEaxI5PErBpJAmKdtjRIzs6JOGKHRaWLi+jdbJPYc2y8RN4qcx5Q== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/recommend@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.23.4.tgz" + integrity sha512-1t6glwKVCkjvBNlng2itTf8fwaLSqkL4JaMENgR3WTGR8mmW2akocUy/ZYSQcG4TcR7qu4zW2UMGAwLoWoflgQ== + dependencies: + "@algolia/client-common" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +"@algolia/requester-browser-xhr@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.23.4.tgz" + integrity sha512-UUuizcgc5+VSY8hqzDFVdJ3Wcto03lpbFRGPgW12pHTlUQHUTADtIpIhkLLOZRCjXmCVhtr97Z+eR6LcRYXa3Q== + dependencies: + "@algolia/client-common" "5.23.4" + +"@algolia/requester-fetch@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.23.4.tgz" + integrity sha512-UhDg6elsek6NnV5z4VG1qMwR6vbp+rTMBEnl/v4hUyXQazU+CNdYkl++cpdmLwGI/7nXc28xtZiL90Es3I7viQ== + dependencies: + "@algolia/client-common" "5.23.4" + +"@algolia/requester-node-http@5.23.4": + version "5.23.4" + resolved "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.23.4.tgz" + integrity sha512-jXGzGBRUS0oywQwnaCA6mMDJO7LoC3dYSLsyNfIqxDR4SNGLhtg3je0Y31lc24OA4nYyKAYgVLtjfrpcpsWShg== + dependencies: + "@algolia/client-common" "5.23.4" + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/code-frame@^7.5.5": + version "7.24.7" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.26.8": + version "7.26.8" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz" + integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== + +"@babel/compat-data@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.27.1.tgz#db7cf122745e0a332c44e847ddc4f5e5221a43f6" + integrity sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A== + +"@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.19.1", "@babel/core@^7.24.4": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.2.0.tgz" + integrity sha512-7pvAdC4B+iKjFFp9Ztj0QgBndJ++qaMeonT185wAqUnhipw8idm9Rv1UMyBuKtYjfl6ORNkgEgcsYLfHX/GpLw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.0" + "@babel/helpers" "^7.2.0" + "@babel/parser" "^7.2.0" + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.6" + "@babel/types" "^7.2.0" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.10" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.23.9": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.27.1.tgz#89de51e86bd12246003e3524704c49541b16c3e6" + integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.27.1" + "@babel/helper-compilation-targets" "^7.27.1" + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helpers" "^7.27.1" + "@babel/parser" "^7.27.1" + "@babel/template" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@^7.26.0": + version "7.26.10" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz" + integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.10" + "@babel/helper-compilation-targets" "^7.26.5" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.10" + "@babel/parser" "^7.26.10" + "@babel/template" "^7.26.9" + "@babel/traverse" "^7.26.10" + "@babel/types" "^7.26.10" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@7.2.0", "@babel/generator@^7.0.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.2.0.tgz" + integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== + dependencies: + "@babel/types" "^7.2.0" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/generator@^7.19.1": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" + integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== + dependencies: + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/generator@^7.2.0", "@babel/generator@^7.26.0", "@babel/generator@^7.26.10", "@babel/generator@^7.26.3", "@babel/generator@^7.27.0", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz" + integrity sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw== + dependencies: + "@babel/parser" "^7.27.0" + "@babel/types" "^7.27.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/generator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.1.tgz#862d4fad858f7208edd487c28b58144036b76230" + integrity sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w== + dependencies: + "@babel/parser" "^7.27.1" + "@babel/types" "^7.27.1" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz" + integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g== + dependencies: + "@babel/types" "^7.25.9" + +"@babel/helper-annotate-as-pure@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz#4345d81a9a46a6486e24d069469f13e60445c05d" + integrity sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.9", "@babel/helper-compilation-targets@^7.26.5": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz" + integrity sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA== + dependencies: + "@babel/compat-data" "^7.26.8" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-compilation-targets@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.1.tgz#eac1096c7374f161e4f33fc8ae38f4ddf122087a" + integrity sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g== + dependencies: + "@babel/compat-data" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.25.9", "@babel/helper-create-class-features-plugin@^7.27.0": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz" + integrity sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/helper-replace-supers" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/traverse" "^7.27.0" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281" + integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.27.1" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.0.tgz" + integrity sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + regexpu-core "^6.2.0" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.3", "@babel/helper-define-polyfill-provider@^0.6.4": + version "0.6.4" + resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz" + integrity sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-function-name@^7.7.4": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-member-expression-to-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz" + integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-member-expression-to-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" + integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.21.2": + version "7.21.2" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz" + integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.2" + "@babel/types" "^7.21.2" + +"@babel/helper-module-transforms@^7.25.9", "@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-module-transforms@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz#e1663b8b71d2de948da5c4fb2a20ca4f3ec27a6f" + integrity sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-optimise-call-expression@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz" + integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ== + dependencies: + "@babel/types" "^7.25.9" + +"@babel/helper-optimise-call-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" + integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.26.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz" + integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== + +"@babel/helper-plugin-utils@^7.20.2": + version "7.20.2" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== + +"@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-remap-async-to-generator@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz" + integrity sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-wrap-function" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-replace-supers@^7.25.9", "@babel/helper-replace-supers@^7.26.5": + version "7.26.5" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz" + integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/traverse" "^7.26.5" + +"@babel/helper-replace-supers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" + integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== + dependencies: + "@babel/types" "^7.20.2" + +"@babel/helper-skip-transparent-expression-wrappers@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz" + integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" + integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-split-export-declaration@^7.18.6", "@babel/helper-split-export-declaration@^7.7.4": + version "7.24.7" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.19.1", "@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helper-wrap-function@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz" + integrity sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g== + dependencies: + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helpers@^7.2.0": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz" + integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg== + dependencies: + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" + +"@babel/helpers@^7.26.10": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz" + integrity sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg== + dependencies: + "@babel/template" "^7.27.0" + "@babel/types" "^7.27.0" + +"@babel/helpers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.1.tgz#ffc27013038607cdba3288e692c3611c06a18aa4" + integrity sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ== + dependencies: + "@babel/template" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.2.0", "@babel/parser@^7.20.15", "@babel/parser@^7.26", "@babel/parser@^7.26.0", "@babel/parser@^7.26.10", "@babel/parser@^7.26.3", "@babel/parser@^7.27.0": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz" + integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== + dependencies: + "@babel/types" "^7.27.0" + +"@babel/parser@^7.20.7": + version "7.21.2" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz" + integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== + +"@babel/parser@^7.23.9", "@babel/parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.1.tgz#c55d5bed74449d1223701f1869b9ee345cc94cc9" + integrity sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/parser@^7.24.4": + version "7.24.4" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== + +"@babel/parser@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" + integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== + dependencies: + "@babel/types" "^7.28.6" + +"@babel/parser@^7.7.4": + version "7.21.4" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz" + integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz" + integrity sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz" + integrity sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.9": + version "7.25.9" + 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.25.9.tgz" + integrity sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz" + integrity sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/plugin-transform-optional-chaining" "^7.25.9" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz" + integrity sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + 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== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-flow@^7.18.6", "@babel/plugin-syntax-flow@^7.7.4": + version "7.21.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.21.4.tgz" + integrity sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-flow@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz" + integrity sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-assertions@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz" + integrity sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-import-attributes@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz" + integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.0.0": + version "7.21.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz" + integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.25.9", "@babel/plugin-syntax-jsx@^7.7.2": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz" + integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.0.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.2.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.0.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.0.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.18.6", "@babel/plugin-syntax-typescript@^7.25.9", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + 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== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz" + integrity sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-async-generator-functions@^7.26.8": + version "7.26.8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz" + integrity sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-remap-async-to-generator" "^7.25.9" + "@babel/traverse" "^7.26.8" + +"@babel/plugin-transform-async-to-generator@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz" + integrity sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-remap-async-to-generator" "^7.25.9" + +"@babel/plugin-transform-block-scoped-functions@^7.26.5": + version "7.26.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz" + integrity sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + +"@babel/plugin-transform-block-scoping@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz" + integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-block-scoping@^7.25.9": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.0.tgz" + integrity sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + +"@babel/plugin-transform-class-properties@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz" + integrity sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-class-static-block@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz" + integrity sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-classes@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz" + integrity sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-replace-supers" "^7.25.9" + "@babel/traverse" "^7.25.9" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz" + integrity sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/template" "^7.25.9" + +"@babel/plugin-transform-destructuring@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz" + integrity sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-dotall-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz" + integrity sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-duplicate-keys@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz" + integrity sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz" + integrity sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-dynamic-import@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz" + integrity sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-exponentiation-operator@^7.26.3": + version "7.26.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz" + integrity sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-export-namespace-from@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz" + integrity sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-flow-strip-types@^7.2.0": + version "7.21.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz" + integrity sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-flow" "^7.18.6" + +"@babel/plugin-transform-flow-strip-types@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz" + integrity sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-flow" "^7.22.5" + +"@babel/plugin-transform-for-of@^7.26.9": + version "7.26.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz" + integrity sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + +"@babel/plugin-transform-function-name@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz" + integrity sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA== + dependencies: + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-transform-json-strings@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz" + integrity sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz" + integrity sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-logical-assignment-operators@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz" + integrity sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-member-expression-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz" + integrity sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-modules-amd@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz" + integrity sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-modules-commonjs@^7.18.6", "@babel/plugin-transform-modules-commonjs@^7.25.9", "@babel/plugin-transform-modules-commonjs@^7.26.3": + version "7.26.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz" + integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ== + dependencies: + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-modules-commonjs@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz#8e44ed37c2787ecc23bdc367f49977476614e832" + integrity sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-modules-commonjs@^7.8.3": + version "7.21.2" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz" + integrity sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA== + dependencies: + "@babel/helper-module-transforms" "^7.21.2" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/helper-simple-access" "^7.20.2" + +"@babel/plugin-transform-modules-systemjs@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz" + integrity sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-transform-modules-umd@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz" + integrity sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz" + integrity sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-new-target@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz" + integrity sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.26.6": + version "7.26.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz" + integrity sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + +"@babel/plugin-transform-numeric-separator@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz" + integrity sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-object-rest-spread@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz" + integrity sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg== + dependencies: + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-transform-parameters" "^7.25.9" + +"@babel/plugin-transform-object-super@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz" + integrity sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-replace-supers" "^7.25.9" + +"@babel/plugin-transform-optional-catch-binding@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz" + integrity sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-optional-chaining@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz" + integrity sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + +"@babel/plugin-transform-parameters@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz" + integrity sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-private-methods@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz" + integrity sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-private-property-in-object@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz" + integrity sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-property-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz" + integrity sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-react-display-name@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz" + integrity sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-react-jsx-development@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz" + integrity sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.25.9" + +"@babel/plugin-transform-react-jsx@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz" + integrity sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-syntax-jsx" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/plugin-transform-react-pure-annotations@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz" + integrity sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-regenerator@^7.25.9": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.0.tgz" + integrity sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-regexp-modifiers@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz" + integrity sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-reserved-words@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz" + integrity sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-shorthand-properties@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz" + integrity sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-spread@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz" + integrity sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + +"@babel/plugin-transform-sticky-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz" + integrity sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-template-literals@^7.26.8": + version "7.26.8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz" + integrity sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + +"@babel/plugin-transform-typeof-symbol@^7.26.7": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.0.tgz" + integrity sha512-+LLkxA9rKJpNoGsbLnAgOCdESl73vwYn+V6b+5wHbrE7OGKVDPHIQvbFSzqE6rwqaCw2RE+zdJrlLkcf8YOA0w== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + +"@babel/plugin-transform-typescript@^7.25.9", "@babel/plugin-transform-typescript@^7.27.0": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.0.tgz" + integrity sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-create-class-features-plugin" "^7.27.0" + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/plugin-syntax-typescript" "^7.25.9" + +"@babel/plugin-transform-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz#d3bb65598bece03f773111e88cc4e8e5070f1140" + integrity sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.27.1" + +"@babel/plugin-transform-unicode-escapes@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz" + integrity sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-property-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz" + integrity sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz" + integrity sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-sets-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz" + integrity sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/preset-env@^7.22.4", "@babel/preset-env@^7.26.9": + version "7.26.9" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz" + integrity sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ== + dependencies: + "@babel/compat-data" "^7.26.8" + "@babel/helper-compilation-targets" "^7.26.5" + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.9" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.9" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.9" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.9" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.9" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions" "^7.26.0" + "@babel/plugin-syntax-import-attributes" "^7.26.0" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.25.9" + "@babel/plugin-transform-async-generator-functions" "^7.26.8" + "@babel/plugin-transform-async-to-generator" "^7.25.9" + "@babel/plugin-transform-block-scoped-functions" "^7.26.5" + "@babel/plugin-transform-block-scoping" "^7.25.9" + "@babel/plugin-transform-class-properties" "^7.25.9" + "@babel/plugin-transform-class-static-block" "^7.26.0" + "@babel/plugin-transform-classes" "^7.25.9" + "@babel/plugin-transform-computed-properties" "^7.25.9" + "@babel/plugin-transform-destructuring" "^7.25.9" + "@babel/plugin-transform-dotall-regex" "^7.25.9" + "@babel/plugin-transform-duplicate-keys" "^7.25.9" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.9" + "@babel/plugin-transform-dynamic-import" "^7.25.9" + "@babel/plugin-transform-exponentiation-operator" "^7.26.3" + "@babel/plugin-transform-export-namespace-from" "^7.25.9" + "@babel/plugin-transform-for-of" "^7.26.9" + "@babel/plugin-transform-function-name" "^7.25.9" + "@babel/plugin-transform-json-strings" "^7.25.9" + "@babel/plugin-transform-literals" "^7.25.9" + "@babel/plugin-transform-logical-assignment-operators" "^7.25.9" + "@babel/plugin-transform-member-expression-literals" "^7.25.9" + "@babel/plugin-transform-modules-amd" "^7.25.9" + "@babel/plugin-transform-modules-commonjs" "^7.26.3" + "@babel/plugin-transform-modules-systemjs" "^7.25.9" + "@babel/plugin-transform-modules-umd" "^7.25.9" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.9" + "@babel/plugin-transform-new-target" "^7.25.9" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.26.6" + "@babel/plugin-transform-numeric-separator" "^7.25.9" + "@babel/plugin-transform-object-rest-spread" "^7.25.9" + "@babel/plugin-transform-object-super" "^7.25.9" + "@babel/plugin-transform-optional-catch-binding" "^7.25.9" + "@babel/plugin-transform-optional-chaining" "^7.25.9" + "@babel/plugin-transform-parameters" "^7.25.9" + "@babel/plugin-transform-private-methods" "^7.25.9" + "@babel/plugin-transform-private-property-in-object" "^7.25.9" + "@babel/plugin-transform-property-literals" "^7.25.9" + "@babel/plugin-transform-regenerator" "^7.25.9" + "@babel/plugin-transform-regexp-modifiers" "^7.26.0" + "@babel/plugin-transform-reserved-words" "^7.25.9" + "@babel/plugin-transform-shorthand-properties" "^7.25.9" + "@babel/plugin-transform-spread" "^7.25.9" + "@babel/plugin-transform-sticky-regex" "^7.25.9" + "@babel/plugin-transform-template-literals" "^7.26.8" + "@babel/plugin-transform-typeof-symbol" "^7.26.7" + "@babel/plugin-transform-unicode-escapes" "^7.25.9" + "@babel/plugin-transform-unicode-property-regex" "^7.25.9" + "@babel/plugin-transform-unicode-regex" "^7.25.9" + "@babel/plugin-transform-unicode-sets-regex" "^7.25.9" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.11.0" + babel-plugin-polyfill-regenerator "^0.6.1" + core-js-compat "^3.40.0" + semver "^6.3.1" + +"@babel/preset-flow@^7.7.4": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.22.5.tgz" + integrity sha512-ta2qZ+LSiGCrP5pgcGt8xMnnkXQrq8Sa4Ulhy06BOlF5QbLw9q5hIx7bn5MrsvyTGAfh6kTOo07Q+Pfld/8Y5Q== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-transform-flow-strip-types" "^7.22.5" + +"@babel/preset-modules@0.1.6-no-external-plugins": + 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== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.18.6": + version "7.26.3" + resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz" + integrity sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-transform-react-display-name" "^7.25.9" + "@babel/plugin-transform-react-jsx" "^7.25.9" + "@babel/plugin-transform-react-jsx-development" "^7.25.9" + "@babel/plugin-transform-react-pure-annotations" "^7.25.9" + +"@babel/preset-typescript@^7.18.6": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.0.tgz" + integrity sha512-vxaPFfJtHhgeOVXRKuHpHPAOgymmy8V8I65T1q53R7GCZlefKeCaTyDs3zOPHTTbmquvNlQYC5klEvWsBAtrBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-syntax-jsx" "^7.25.9" + "@babel/plugin-transform-modules-commonjs" "^7.26.3" + "@babel/plugin-transform-typescript" "^7.27.0" + +"@babel/preset-typescript@^7.26.0": + version "7.26.0" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz" + integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-syntax-jsx" "^7.25.9" + "@babel/plugin-transform-modules-commonjs" "^7.25.9" + "@babel/plugin-transform-typescript" "^7.25.9" + +"@babel/preset-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz#190742a6428d282306648a55b0529b561484f912" + integrity sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/plugin-transform-modules-commonjs" "^7.27.1" + "@babel/plugin-transform-typescript" "^7.27.1" + +"@babel/register@^7.0.0": + version "7.21.0" + resolved "https://registry.npmjs.org/@babel/register/-/register-7.21.0.tgz" + integrity sha512-9nKsPmYDi5DidAqJaQooxIhsLJiNMkGr8ypQ8Uic7cIox7UCDsM7HuUGxdGT7mSDTYbqzIdsOWzfBton/YJrMw== + dependencies: + clone-deep "^4.0.1" + find-cache-dir "^2.0.0" + make-dir "^2.1.0" + pirates "^4.0.5" + source-map-support "^0.5.16" + +"@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz" + integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.21.0": + version "7.22.3" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz" + integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.1.2", "@babel/template@^7.18.10", "@babel/template@^7.25.9", "@babel/template@^7.26.9", "@babel/template@^7.27.0", "@babel/template@^7.3.3": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz" + integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/parser" "^7.27.0" + "@babel/types" "^7.27.0" + +"@babel/template@^7.20.7": + version "7.20.7" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/template@^7.24.7", "@babel/template@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.1.tgz#b9e4f55c17a92312774dfbdde1b3c01c547bbae2" + integrity sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.1.6", "@babel/traverse@^7.19.1", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.27.0": + version "7.27.0" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz" + integrity sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.27.0" + "@babel/parser" "^7.27.0" + "@babel/template" "^7.27.0" + "@babel/types" "^7.27.0" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/traverse@^7.19.0", "@babel/traverse@^7.21.2": + version "7.26.4" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz" + integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.3" + "@babel/parser" "^7.26.3" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.3" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/traverse@^7.2.0", "@babel/traverse@^7.7.2": + version "7.7.4" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/traverse@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.1.tgz#4db772902b133bbddd1c4f7a7ee47761c1b9f291" + integrity sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.27.1" + "@babel/parser" "^7.27.1" + "@babel/template" "^7.27.1" + "@babel/types" "^7.27.1" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@7.26.3", "@babel/types@^7.0.0", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.2", "@babel/types@^7.24.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.10", "@babel/types@^7.26.3", "@babel/types@^7.27.0", "@babel/types@^7.27.1", "@babel/types@^7.28.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.4": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0" + integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@esbuild/aix-ppc64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz#499600c5e1757a524990d5d92601f0ac3ce87f64" + integrity sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ== + +"@esbuild/android-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz#b9b8231561a1dfb94eb31f4ee056b92a985c324f" + integrity sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g== + +"@esbuild/android-arm@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.0.tgz#ca6e7888942505f13e88ac9f5f7d2a72f9facd2b" + integrity sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g== + +"@esbuild/android-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.0.tgz#e765ea753bac442dfc9cb53652ce8bd39d33e163" + integrity sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg== + +"@esbuild/darwin-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz" + integrity sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw== + +"@esbuild/darwin-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz#91979d98d30ba6e7d69b22c617cc82bdad60e47a" + integrity sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg== + +"@esbuild/freebsd-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz#b97e97073310736b430a07b099d837084b85e9ce" + integrity sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w== + +"@esbuild/freebsd-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz#f3b694d0da61d9910ec7deff794d444cfbf3b6e7" + integrity sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A== + +"@esbuild/linux-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz#f921f699f162f332036d5657cad9036f7a993f73" + integrity sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg== + +"@esbuild/linux-arm@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz#cc49305b3c6da317c900688995a4050e6cc91ca3" + integrity sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg== + +"@esbuild/linux-ia32@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz#3e0736fcfab16cff042dec806247e2c76e109e19" + integrity sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg== + +"@esbuild/linux-loong64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz#ea2bf730883cddb9dfb85124232b5a875b8020c7" + integrity sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw== + +"@esbuild/linux-mips64el@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz#4cababb14eede09248980a2d2d8b966464294ff1" + integrity sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ== + +"@esbuild/linux-ppc64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz#8860a4609914c065373a77242e985179658e1951" + integrity sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw== + +"@esbuild/linux-riscv64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz#baf26e20bb2d38cfb86ee282dff840c04f4ed987" + integrity sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA== + +"@esbuild/linux-s390x@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz#8323afc0d6cb1b6dc6e9fd21efd9e1542c3640a4" + integrity sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA== + +"@esbuild/linux-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz#08fcf60cb400ed2382e9f8e0f5590bac8810469a" + integrity sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw== + +"@esbuild/netbsd-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz#935c6c74e20f7224918fbe2e6c6fe865b6c6ea5b" + integrity sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw== + +"@esbuild/netbsd-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz#414677cef66d16c5a4d210751eb2881bb9c1b62b" + integrity sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA== + +"@esbuild/openbsd-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz#8fd55a4d08d25cdc572844f13c88d678c84d13f7" + integrity sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw== + +"@esbuild/openbsd-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz#0c48ddb1494bbc2d6bcbaa1429a7f465fa1dedde" + integrity sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg== + +"@esbuild/sunos-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz#86ff9075d77962b60dd26203d7352f92684c8c92" + integrity sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg== + +"@esbuild/win32-arm64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz#849c62327c3229467f5b5cd681bf50588442e96c" + integrity sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw== + +"@esbuild/win32-ia32@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz#f62eb480cd7cca088cb65bb46a6db25b725dc079" + integrity sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA== + +"@esbuild/win32-x64@0.25.0": + version "0.25.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz#c8e119a30a7c8d60b9d2e22d2073722dde3b710b" + integrity sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0": + version "4.11.1" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/config-array@^0.19.0": + version "0.19.1" + resolved "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz" + integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA== + dependencies: + "@eslint/object-schema" "^2.1.5" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.9.0": + version "0.9.1" + resolved "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz" + integrity sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@eslint/js@9.17.0", "@eslint/js@^9.13.0": + version "9.17.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz" + integrity sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w== + +"@eslint/object-schema@^2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz" + integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ== + +"@eslint/plugin-kit@^0.2.3": + version "0.2.4" + resolved "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz" + integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg== + dependencies: + levn "^0.4.1" + +"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": + version "9.3.0" + resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.1.0": + version "5.1.0" + resolved "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + 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" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + +"@jest/console@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz" + integrity sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg== + dependencies: + "@jest/types" "^29.0.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.0.3" + jest-util "^29.0.3" + slash "^3.0.0" + +"@jest/console@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz" + integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + slash "^3.0.0" + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz" + integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/reporters" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^28.1.3" + jest-config "^28.1.3" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-resolve-dependencies "^28.1.3" + jest-runner "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + jest-watcher "^28.1.3" + micromatch "^4.0.4" + pretty-format "^28.1.3" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/core@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz" + integrity sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ== + dependencies: + "@jest/console" "^29.0.3" + "@jest/reporters" "^29.0.3" + "@jest/test-result" "^29.0.3" + "@jest/transform" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.0.0" + jest-config "^29.0.3" + jest-haste-map "^29.0.3" + jest-message-util "^29.0.3" + jest-regex-util "^29.0.0" + jest-resolve "^29.0.3" + jest-resolve-dependencies "^29.0.3" + jest-runner "^29.0.3" + jest-runtime "^29.0.3" + jest-snapshot "^29.0.3" + jest-util "^29.0.3" + jest-validate "^29.0.3" + jest-watcher "^29.0.3" + micromatch "^4.0.4" + pretty-format "^29.0.3" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/core@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz" + integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== + dependencies: + "@jest/console" "^29.5.0" + "@jest/reporters" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.5.0" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-resolve-dependencies "^29.5.0" + jest-runner "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + jest-watcher "^29.5.0" + micromatch "^4.0.4" + pretty-format "^29.5.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/diff-sequences@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be" + integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw== + +"@jest/environment@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz" + integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== + dependencies: + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + +"@jest/environment@^29.0.3", "@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/environment@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz" + integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== + dependencies: + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-mock "^29.5.0" + +"@jest/expect-utils@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.0.5.tgz#9d42e4b8bc80367db30abc6c42b2cb14073f66fc" + integrity sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew== + dependencies: + "@jest/get-type" "30.0.1" + +"@jest/expect-utils@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz" + integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== + dependencies: + jest-get-type "^28.0.2" + +"@jest/expect-utils@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz" + integrity sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q== + dependencies: + jest-get-type "^29.0.0" + +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz" + integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== + dependencies: + expect "^28.1.3" + jest-snapshot "^28.1.3" + +"@jest/expect@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz" + integrity sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ== + dependencies: + expect "^29.0.3" + jest-snapshot "^29.0.3" + +"@jest/expect@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz" + integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== + dependencies: + expect "^29.5.0" + jest-snapshot "^29.5.0" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz" + integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== + dependencies: + "@jest/types" "^28.1.3" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +"@jest/fake-timers@^29.0.3", "@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/fake-timers@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz" + integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== + dependencies: + "@jest/types" "^29.5.0" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-util "^29.5.0" + +"@jest/get-type@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.0.1.tgz#0d32f1bbfba511948ad247ab01b9007724fc9f52" + integrity sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw== + +"@jest/globals@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz" + integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/types" "^28.1.3" + +"@jest/globals@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz" + integrity sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w== + dependencies: + "@jest/environment" "^29.0.3" + "@jest/expect" "^29.0.3" + "@jest/types" "^29.0.3" + jest-mock "^29.0.3" + +"@jest/globals@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz" + integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/types" "^29.5.0" + jest-mock "^29.5.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/pattern@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/pattern/-/pattern-30.0.1.tgz#d5304147f49a052900b4b853dedb111d080e199f" + integrity sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA== + dependencies: + "@types/node" "*" + jest-regex-util "30.0.1" + +"@jest/reporters@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz" + integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + jest-worker "^28.1.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/reporters@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz" + integrity sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.0.3" + "@jest/test-result" "^29.0.3" + "@jest/transform" "^29.0.3" + "@jest/types" "^29.0.3" + "@jridgewell/trace-mapping" "^0.3.15" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.0.3" + jest-util "^29.0.3" + jest-worker "^29.0.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/reporters@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz" + integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + jest-worker "^29.5.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-30.0.5.tgz#7bdf69fc5a368a5abdb49fd91036c55225846473" + integrity sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA== + dependencies: + "@sinclair/typebox" "^0.34.0" + +"@jest/schemas@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz" + integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== + dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== + dependencies: + "@jridgewell/trace-mapping" "^0.3.13" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/source-map@^29.0.0": + version "29.0.0" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz" + integrity sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ== + dependencies: + "@jridgewell/trace-mapping" "^0.3.15" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/source-map@^29.4.3": + version "29.4.3" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz" + integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.15" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-result@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz" + integrity sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg== + dependencies: + "@jest/console" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-result@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz" + integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== + dependencies: + "@jest/console" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz" + integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== + dependencies: + "@jest/test-result" "^28.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + slash "^3.0.0" + +"@jest/test-sequencer@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz" + integrity sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ== + dependencies: + "@jest/test-result" "^29.0.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.0.3" + slash "^3.0.0" + +"@jest/test-sequencer@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz" + integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== + dependencies: + "@jest/test-result" "^29.5.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + slash "^3.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz" + integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + +"@jest/transform@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz" + integrity sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.0.3" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.0.3" + jest-regex-util "^29.0.0" + jest-util "^29.0.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + +"@jest/transform@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz" + integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.0.5.tgz#29a33a4c036e3904f1cfd94f6fe77f89d2e1cc05" + integrity sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ== + dependencies: + "@jest/pattern" "30.0.1" + "@jest/schemas" "30.0.5" + "@types/istanbul-lib-coverage" "^2.0.6" + "@types/istanbul-reports" "^3.0.4" + "@types/node" "*" + "@types/yargs" "^17.0.33" + chalk "^4.1.2" + +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + +"@jest/types@^28.1.3": + version "28.1.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz" + integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== + dependencies: + "@jest/schemas" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jest/types@^29.0.3", "@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== + dependencies: + "@jest/schemas" "^29.4.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.12": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.8" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@jridgewell/trace-mapping@^0.3.13": + version "0.3.18" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@modelcontextprotocol/sdk@^1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.9.0.tgz" + integrity sha512-Jq2EUCQpe0iyO5FGpzVYDNFR6oR53AIrwph9yWl7uSc7IWUMsrmpmSaTGra5hQNunXpM+9oit85p924jWuHzUA== + dependencies: + content-type "^1.0.5" + cors "^2.8.5" + cross-spawn "^7.0.3" + eventsource "^3.0.2" + express "^5.0.1" + express-rate-limit "^7.5.0" + pkce-challenge "^5.0.0" + raw-body "^3.0.0" + zod "^3.23.8" + zod-to-json-schema "^3.24.1" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@parcel/watcher@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.1.0.tgz" + integrity sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw== + dependencies: + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^3.2.1" + node-gyp-build "^4.3.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@puppeteer/browsers@2.10.2": + version "2.10.2" + resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.2.tgz" + integrity sha512-i4Ez+s9oRWQbNjtI/3+jxr7OH508mjAKvza0ekPJem0ZtmsYHP3B5dq62+IaBHKaGCOuqJxXzvFLUhJvQ6jtsQ== + dependencies: + debug "^4.4.0" + extract-zip "^2.0.1" + progress "^2.0.3" + proxy-agent "^6.5.0" + semver "^7.7.1" + tar-fs "^3.0.8" + yargs "^17.7.2" + +"@rollup/rollup-android-arm-eabi@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz#661a45a4709c70e59e596ec78daa9cb8b8d27604" + integrity sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA== + +"@rollup/rollup-android-arm64@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz#128fe8dd510d880cf98b4cb6c7add326815a0c4b" + integrity sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg== + +"@rollup/rollup-darwin-arm64@4.34.9": + version "4.34.9" + resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz" + integrity sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ== + +"@rollup/rollup-darwin-x64@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz#c2fe3d85fffe47f0ed0f076b3563ada22c8af19c" + integrity sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q== + +"@rollup/rollup-freebsd-arm64@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz#d95bd8f6eaaf829781144fc8bd2d5d71d9f6a9f5" + integrity sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw== + +"@rollup/rollup-freebsd-x64@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz#c3576c6011656e4966ded29f051edec636b44564" + integrity sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g== + +"@rollup/rollup-linux-arm-gnueabihf@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz#48c87d0dee4f8dc9591a416717f91b4a89d77e3d" + integrity sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg== + +"@rollup/rollup-linux-arm-musleabihf@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz#f4c4e7c03a7767f2e5aa9d0c5cfbf5c0f59f2d41" + integrity sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA== + +"@rollup/rollup-linux-arm64-gnu@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz#1015c9d07a99005025d13b8622b7600029d0b52f" + integrity sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw== + +"@rollup/rollup-linux-arm64-musl@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz#8f895eb5577748fc75af21beae32439626e0a14c" + integrity sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A== + +"@rollup/rollup-linux-loongarch64-gnu@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz#c9cd5dbbdc6b3ca4dbeeb0337498cf31949004a0" + integrity sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg== + +"@rollup/rollup-linux-powerpc64le-gnu@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz#7ebb5b4441faa17843a210f7d0583a20c93b40e4" + integrity sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA== + +"@rollup/rollup-linux-riscv64-gnu@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz#10f5d7349fbd2fe78f9e36ecc90aab3154435c8d" + integrity sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg== + +"@rollup/rollup-linux-s390x-gnu@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz#196347d2fa20593ab09d0b7e2589fb69bdf742c6" + integrity sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ== + +"@rollup/rollup-linux-x64-gnu@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz#7193cbd8d128212b8acda37e01b39d9e96259ef8" + integrity sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A== + +"@rollup/rollup-linux-x64-musl@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz#29a6867278ca0420b891574cfab98ecad70c59d1" + integrity sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA== + +"@rollup/rollup-win32-arm64-msvc@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz#89427dcac0c8e3a6d32b13a03a296a275d0de9a9" + integrity sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q== + +"@rollup/rollup-win32-ia32-msvc@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz#ecb9711ba2b6d2bf6ee51265abe057ab90913deb" + integrity sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w== + +"@rollup/rollup-win32-x64-msvc@4.34.9": + version "4.34.9" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz#1973871850856ae72bc678aeb066ab952330e923" + integrity sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw== + +"@selderee/plugin-htmlparser2@^0.11.0": + version "0.11.0" + resolved "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz" + integrity sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ== + dependencies: + domhandler "^5.0.3" + selderee "^0.11.0" + +"@sideway/address@^4.1.5": + version "4.1.5" + resolved "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sinclair/typebox@^0.24.1": + version "0.24.42" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.42.tgz" + integrity sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw== + +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinclair/typebox@^0.34.0": + version "0.34.38" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.38.tgz#2365df7c23406a4d79413a766567bfbca708b49d" + integrity sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA== + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.2.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.2.0.tgz" + integrity sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@testing-library/dom@^8.5.0": + version "8.18.1" + resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-8.18.1.tgz" + integrity sha512-oEvsm2B/WtcHKE+IcEeeCqNU/ltFGaVyGbpcm4g/2ytuT49jrlH9x5qRKL/H3A6yfM4YAbSbC0ceT5+9CEXnLg== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^4.2.0" + aria-query "^5.0.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.4.4" + pretty-format "^27.0.2" + +"@testing-library/react@^13.4.0": + version "13.4.0" + resolved "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz" + integrity sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^8.5.0" + "@types/react-dom" "^18.0.0" + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@tootallnate/quickjs-emscripten@^0.23.0": + version "0.23.0" + resolved "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz" + integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@tsconfig/node18-strictest@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@tsconfig/node18-strictest/-/node18-strictest-1.0.0.tgz" + integrity sha512-bOuNKwO4Fzbt+Su5wqI9zNHwx5C25gLnutwVQA1sBZk0cW8UjVPVcwzIUhJIIJDUx7zDEbAwdCD2HfvIsV8dYg== + +"@tsconfig/strictest@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@tsconfig/strictest/-/strictest-2.0.5.tgz" + integrity sha512-ec4tjL2Rr0pkZ5hww65c+EEPYwxOi4Ryv+0MtjeaSQRJyq322Q27eOQiFbuNgw2hpL4hB1/W/HBGk3VKS43osg== + +"@types/aria-query@^4.2.0": + version "4.2.2" + resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz" + integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== + +"@types/babel__code-frame@^7.0.6": + version "7.0.6" + resolved "https://registry.npmjs.org/@types/babel__code-frame/-/babel__code-frame-7.0.6.tgz" + integrity sha512-Anitqkl3+KrzcW2k77lRlg/GfLZLWXBuNgbEcIOU6M92yw42vsd3xV/Z/yAHEj8m+KUjL6bWOVOFqX8PFPJ4LA== + +"@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.18.2" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz" + integrity sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg== + dependencies: + "@babel/types" "^7.3.0" + +"@types/eslint@^8.56.12": + version "8.56.12" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz" + integrity sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.5" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/estree@1.0.6", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/fbt@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@types/fbt/-/fbt-1.0.4.tgz" + integrity sha512-KBaaLu4hEIBaCyQ3L2KP6JujD+tmMuPZ10YpgmGgqMaM8TESYR2TOJNvG+GYiWUhGkp38Y+62VZ1wJ97MPvt+A== + dependencies: + "@types/react" "*" + +"@types/glob@^8.1.0": + version "8.1.0" + resolved "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz" + integrity sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w== + dependencies: + "@types/minimatch" "^5.1.2" + "@types/node" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.5" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/html-to-text@^9.0.4": + version "9.0.4" + resolved "https://registry.npmjs.org/@types/html-to-text/-/html-to-text-9.0.4.tgz" + integrity sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ== + +"@types/invariant@^2.2.35": + version "2.2.35" + resolved "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.35.tgz" + integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-coverage@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/istanbul-reports@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^28.1.6": + version "28.1.8" + resolved "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz" + integrity sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw== + dependencies: + expect "^28.0.0" + pretty-format "^28.0.0" + +"@types/jest@^29.0.3": + version "29.0.3" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz" + integrity sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/jest@^29.5.14": + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/jest@^30.0.0": + version "30.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-30.0.0.tgz#5e85ae568006712e4ad66f25433e9bdac8801f1d" + integrity sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA== + dependencies: + expect "^30.0.0" + pretty-format "^30.0.0" + +"@types/jsdom@^20.0.0": + version "20.0.0" + resolved "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.0.tgz" + integrity sha512-YfAchFs0yM1QPDrLm2VHe+WHGtqms3NXnXAMolrgrVP6fgBHHXy1ozAbo/dFtPNtZC/m66bPiCTWYmqp1F14gA== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/minimatch@^5.1.2": + version "5.1.2" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/mocha@^10.0.10", "@types/mocha@^10.0.2": + version "10.0.10" + resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== + +"@types/node@*", "@types/node@^18.7.18": + version "18.7.19" + resolved "https://registry.npmjs.org/@types/node/-/node-18.7.19.tgz" + integrity sha512-Sq1itGUKUX1ap7GgZlrzdBydjbsJL/NSQt/4wkAxUJ7/OS5c2WkoN6WSpWc2Yc5wtKMZOUA0VCs/j2XJadN3HA== + +"@types/node@^20": + version "20.17.10" + resolved "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz" + integrity sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA== + dependencies: + undici-types "~6.19.2" + +"@types/node@^20.2.5": + version "20.2.5" + resolved "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz" + integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ== + +"@types/prettier@^2.1.5": + version "2.7.0" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz" + integrity sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A== + +"@types/prop-types@*": + version "15.7.5" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/react-dom@^18.0.0": + version "18.0.6" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz" + integrity sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "18.0.21" + resolved "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz" + integrity sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@types/semver@^7.5.0": + version "7.5.8" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/stack-utils@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/tough-cookie@*": + version "4.0.2" + resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz" + integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== + +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + +"@types/vscode@^1.96.0": + version "1.96.0" + resolved "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz" + integrity sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^13.0.0": + version "13.0.12" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.12.tgz" + integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^17.0.33": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^17.0.8": + version "17.0.13" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz" + integrity sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg== + dependencies: + "@types/yargs-parser" "*" + +"@types/yauzl@^2.9.1": + version "2.10.3" + resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz" + integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz" + integrity sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/type-utils" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/eslint-plugin@^7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz" + integrity sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "7.4.0" + "@typescript-eslint/type-utils" "7.4.0" + "@typescript-eslint/utils" "7.4.0" + "@typescript-eslint/visitor-keys" "7.4.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/eslint-plugin@^8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz" + integrity sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/type-utils" "8.7.0" + "@typescript-eslint/utils" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz" + integrity sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA== + dependencies: + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + debug "^4.3.4" + +"@typescript-eslint/parser@^7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz" + integrity sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ== + dependencies: + "@typescript-eslint/scope-manager" "7.4.0" + "@typescript-eslint/types" "7.4.0" + "@typescript-eslint/typescript-estree" "7.4.0" + "@typescript-eslint/visitor-keys" "7.4.0" + debug "^4.3.4" + +"@typescript-eslint/parser@^8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz" + integrity sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ== + dependencies: + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/typescript-estree" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz" + integrity sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw== + dependencies: + "@typescript-eslint/types" "7.4.0" + "@typescript-eslint/visitor-keys" "7.4.0" + +"@typescript-eslint/scope-manager@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz" + integrity sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ== + dependencies: + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + +"@typescript-eslint/scope-manager@8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz" + integrity sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg== + dependencies: + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + +"@typescript-eslint/type-utils@7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz" + integrity sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw== + dependencies: + "@typescript-eslint/typescript-estree" "7.4.0" + "@typescript-eslint/utils" "7.4.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/type-utils@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz" + integrity sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ== + dependencies: + "@typescript-eslint/typescript-estree" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/type-utils@8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz" + integrity sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ== + dependencies: + "@typescript-eslint/typescript-estree" "8.7.0" + "@typescript-eslint/utils" "8.7.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz" + integrity sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw== + +"@typescript-eslint/types@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz" + integrity sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw== + +"@typescript-eslint/types@8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz" + integrity sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w== + +"@typescript-eslint/typescript-estree@7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz" + integrity sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg== + dependencies: + "@typescript-eslint/types" "7.4.0" + "@typescript-eslint/visitor-keys" "7.4.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/typescript-estree@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz" + integrity sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg== + dependencies: + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/visitor-keys" "8.18.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/typescript-estree@8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz" + integrity sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg== + dependencies: + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz" + integrity sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "7.4.0" + "@typescript-eslint/types" "7.4.0" + "@typescript-eslint/typescript-estree" "7.4.0" + semver "^7.5.4" + +"@typescript-eslint/utils@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz" + integrity sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.18.1" + "@typescript-eslint/types" "8.18.1" + "@typescript-eslint/typescript-estree" "8.18.1" + +"@typescript-eslint/utils@8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz" + integrity sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/typescript-estree" "8.7.0" + +"@typescript-eslint/visitor-keys@7.4.0": + version "7.4.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz" + integrity sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA== + dependencies: + "@typescript-eslint/types" "7.4.0" + eslint-visitor-keys "^3.4.1" + +"@typescript-eslint/visitor-keys@8.18.1": + version "8.18.1" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz" + integrity sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ== + dependencies: + "@typescript-eslint/types" "8.18.1" + eslint-visitor-keys "^4.2.0" + +"@typescript-eslint/visitor-keys@8.7.0": + version "8.7.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz" + integrity sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ== + dependencies: + "@typescript-eslint/types" "8.7.0" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@vscode/test-cli@^0.0.10": + version "0.0.10" + resolved "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.10.tgz" + integrity sha512-B0mMH4ia+MOOtwNiLi79XhA+MLmUItIC8FckEuKrVAVriIuSWjt7vv4+bF8qVFiNFe4QRfzPaIZk39FZGWEwHA== + dependencies: + "@types/mocha" "^10.0.2" + c8 "^9.1.0" + chokidar "^3.5.3" + enhanced-resolve "^5.15.0" + glob "^10.3.10" + minimatch "^9.0.3" + mocha "^10.2.0" + supports-color "^9.4.0" + yargs "^17.7.2" + +"@vscode/test-electron@^2.4.1": + version "2.4.1" + resolved "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz" + integrity sha512-Gc6EdaLANdktQ1t+zozoBVRynfIsMKMc94Svu1QreOBC8y76x4tvaK32TljrLi1LI2+PK58sDVbL7ALdqf3VRQ== + dependencies: + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.5" + jszip "^3.10.1" + ora "^7.0.1" + semver "^7.6.2" + +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +accepts@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz" + integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== + dependencies: + mime-types "^3.0.0" + negotiator "^1.0.0" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + +acorn@^8.4.1, acorn@^8.7.1: + version "8.8.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +acorn@^8.9.0: + version "8.11.2" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== + +agent-base@6: + version "6.0.2" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + 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" + +algoliasearch@^5.23.3: + version "5.23.4" + resolved "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.23.4.tgz" + integrity sha512-QzAKFHl3fm53s44VHrTdEo0TkpL3XVUYQpnZy1r6/EHvMAyIg+O4hwprzlsNmcCHTNyVcF2S13DAUn7XhkC6qg== + dependencies: + "@algolia/client-abtesting" "5.23.4" + "@algolia/client-analytics" "5.23.4" + "@algolia/client-common" "5.23.4" + "@algolia/client-insights" "5.23.4" + "@algolia/client-personalization" "5.23.4" + "@algolia/client-query-suggestions" "5.23.4" + "@algolia/client-search" "5.23.4" + "@algolia/ingestion" "1.23.4" + "@algolia/monitoring" "1.23.4" + "@algolia/recommend" "5.23.4" + "@algolia/requester-browser-xhr" "5.23.4" + "@algolia/requester-fetch" "5.23.4" + "@algolia/requester-node-http" "5.23.4" + +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0, ansi-styles@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@^3.0.3: + version "3.1.2" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +args@5.0.3: + version "5.0.3" + resolved "https://registry.npmjs.org/args/-/args-5.0.3.tgz" + integrity sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA== + dependencies: + camelcase "5.0.0" + chalk "2.4.2" + leven "2.1.0" + mri "1.1.4" + +aria-query@^5.0.0: + version "5.0.2" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz" + integrity sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q== + +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + +ast-types@^0.13.4: + version "0.13.4" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== + +async@^3.2.3: + version "3.2.6" + resolved "https://registry.npmjs.org/async/-/async-3.2.6.tgz" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axios@^1.6.1: + version "1.7.4" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz" + integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +b4a@^1.6.4: + version "1.6.7" + resolved "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz" + integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg== + +babel-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz" + integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== + dependencies: + "@jest/transform" "^28.1.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^28.1.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-jest@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz" + integrity sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg== + dependencies: + "@jest/transform" "^29.0.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.0.2" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz" + integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== + dependencies: + "@jest/transform" "^29.5.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-fbt-runtime@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/babel-plugin-fbt-runtime/-/babel-plugin-fbt-runtime-1.0.0.tgz" + integrity sha512-gML1rXqIfc+sDf1DWxu1WJjmotBYr6f9vjKwOoetuOukM1o3mTKNAeBFGEYu7iBACkuaXpIi++qW8/URgHnduQ== + dependencies: + "@babel/core" "^7.0.0" + invariant "^2.2.4" + +babel-plugin-fbt@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/babel-plugin-fbt/-/babel-plugin-fbt-1.0.0.tgz" + integrity sha512-Tjpkrt4JJLgtS+x6HzkWdOguH+Pb+pzJmSkBmHIWrjf3x9Pf+xFcQUdAbpDKOtRPgu6QyI9DtDulw0sbgdfYdg== + dependencies: + "@babel/core" "^7.0.0" + "@babel/generator" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-transform-flow-strip-types" "^7.2.0" + "@babel/plugin-transform-modules-commonjs" "^7.8.3" + "@babel/register" "^7.0.0" + "@babel/types" "^7.2.2" + fb-babel-plugin-utils "^0.13.0" + flow-enums-runtime "^0.0.4" + glob "^7.1.6" + invariant "^2.2.4" + jest-docblock "^26.0.0" + nullthrows "^1.1.1" + yargs "^15.3.1" + +babel-plugin-idx@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/babel-plugin-idx/-/babel-plugin-idx-3.0.3.tgz" + integrity sha512-05baCoIGsvZJKemq6KQ4KVFlweEpY4aSY56wk3W781JxCNW3u0KfBElBt26/cPZbHkjF1mnwGIOlFY+9I/VOZA== + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz" + integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.13" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz" + integrity sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.6.4" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.11.0: + version "0.11.1" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz" + integrity sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.3" + core-js-compat "^3.40.0" + +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.4" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz" + integrity sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.4" + +babel-plugin-syntax-hermes-parser@^0.25.1: + version "0.25.1" + resolved "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz" + integrity sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ== + dependencies: + hermes-parser "0.25.1" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz" + integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== + dependencies: + babel-plugin-jest-hoist "^28.1.3" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-jest@^29.0.2, babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +bare-events@^2.2.0, bare-events@^2.5.4: + version "2.5.4" + resolved "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz" + integrity sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA== + +bare-fs@^4.0.1: + version "4.1.3" + resolved "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.3.tgz" + integrity sha512-OeEZYIg+2qepaWLyphaOXHAHKo3xkM8y3BeGAvHdMN8GNWvEAU1Yw6rYpGzu/wDDbKxgEjVeVDpgGhDzaeMpjg== + dependencies: + bare-events "^2.5.4" + bare-path "^3.0.0" + bare-stream "^2.6.4" + +bare-os@^3.0.1: + version "3.6.1" + resolved "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz" + integrity sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g== + +bare-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz" + integrity sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw== + dependencies: + bare-os "^3.0.1" + +bare-stream@^2.6.4: + version "2.6.5" + resolved "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz" + integrity sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA== + dependencies: + streamx "^2.21.0" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +basic-ftp@^5.0.2: + version "5.0.5" + resolved "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz" + integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + +body-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz" + integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg== + dependencies: + bytes "^3.1.2" + content-type "^1.0.5" + debug "^4.4.0" + http-errors "^2.0.0" + iconv-lite "^0.6.3" + on-finished "^2.4.1" + qs "^6.14.0" + raw-body "^3.0.0" + type-is "^2.0.0" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.24.0, browserslist@^4.24.4: + version "4.24.4" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== + dependencies: + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" + +bs-logger@0.x, bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bundle-require@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz" + integrity sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA== + dependencies: + load-tsconfig "^0.2.3" + +bytes@3.1.2, bytes@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +c8@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz" + integrity sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@istanbuljs/schema" "^0.1.3" + find-up "^5.0.0" + foreground-child "^3.1.1" + istanbul-lib-coverage "^3.2.0" + istanbul-lib-report "^3.0.1" + istanbul-reports "^3.1.6" + test-exclude "^6.0.0" + v8-to-istanbul "^9.0.0" + yargs "^17.7.2" + yargs-parser "^21.1.1" + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0, camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001688: + version "1.0.30001715" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz" + integrity sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw== + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@4, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^5.0.0, chalk@^5.3.0: + version "5.4.1" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +cheerio-select@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz" + integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== + dependencies: + boolbase "^1.0.0" + css-select "^5.1.0" + css-what "^6.1.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + +cheerio@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz" + integrity sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.1.0" + encoding-sniffer "^0.2.0" + htmlparser2 "^9.1.0" + parse5 "^7.1.2" + parse5-htmlparser2-tree-adapter "^7.0.0" + parse5-parser-stream "^7.1.2" + undici "^6.19.5" + whatwg-mimetype "^4.0.0" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +chromium-bidi@4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-4.1.1.tgz" + integrity sha512-biR7t4vF3YluE6RlMSk9IWk+b9U+WWyzHp+N2pL9vRTk+UXHYRTVp7jTK58ZNzMLBgoLMHY4QyJMbeuw3eKxqg== + dependencies: + mitt "^3.0.1" + zod "^3.24.1" + +ci-info@^3.2.0: + version "3.4.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz" + integrity sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug== + +ci-info@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.0.tgz#c39b1013f8fdbd28cd78e62318357d02da160cd7" + integrity sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +cli-color@~0.1.6: + version "0.1.7" + resolved "https://registry.npmjs.org/cli-color/-/cli-color-0.1.7.tgz" + integrity sha512-xNaQxWYgI6DD4xIJLn8GY2zDZVbrN0vsU1fEbDNAHZRyceWhpj7A08mYcG1AY92q1Aw0geYkVfiAcEYIZtuTSg== + dependencies: + es5-ext "0.8.x" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-spinners@^2.5.0, cli-spinners@^2.9.0: + version "2.9.2" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.9.0: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concurrently@^7.4.0: + version "7.6.0" + resolved "https://registry.npmjs.org/concurrently/-/concurrently-7.6.0.tgz" + integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw== + dependencies: + chalk "^4.1.0" + date-fns "^2.29.1" + lodash "^4.17.21" + rxjs "^7.0.0" + shell-quote "^1.7.3" + spawn-command "^0.0.2-1" + supports-color "^8.1.0" + tree-kill "^1.2.2" + yargs "^17.3.1" + +consola@^3.4.0: + version "3.4.0" + resolved "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz" + integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA== + +content-disposition@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz" + integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg== + dependencies: + safe-buffer "5.2.1" + +content-type@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0: + version "1.8.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz" + integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== + +cookie@^0.7.1: + version "0.7.2" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + +core-js-compat@^3.40.0: + version "3.41.0" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz" + integrity sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A== + dependencies: + browserslist "^4.24.4" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cosmiconfig@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== + dependencies: + env-paths "^2.2.1" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +cssstyle@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz" + integrity sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg== + dependencies: + rrweb-cssom "^0.6.0" + +csstype@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz" + integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== + +data-uri-to-buffer@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz" + integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw== + +data-urls@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz" + integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== + dependencies: + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + +data-urls@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz" + integrity sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g== + dependencies: + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^12.0.0" + +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +date-fns@^2.29.1: + version "2.30.0" + resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decimal.js@^10.3.1: + version "10.4.1" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.1.tgz" + integrity sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw== + +decimal.js@^10.4.3: + version "10.4.3" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +dedent@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.6.0.tgz#79d52d6389b1ffa67d2bcef59ba51847a9d503b2" + integrity sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA== + +deep-is@^0.1.3: + 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== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +degenerator@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz" + integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== + dependencies: + ast-types "^0.13.4" + escodegen "^2.1.0" + esprima "^4.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0, depd@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz" + integrity sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +devtools-protocol@0.0.1425554: + version "0.0.1425554" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1425554.tgz" + integrity sha512-uRfxR6Nlzdzt0ihVIkV+sLztKgs7rgquY/Mhcv1YNCWDh5IZgl5mnn2aeEnW5stYTE0wwiF4RYVz8eMEpV1SEw== + +diff-sequences@^28.1.1: + version "28.1.1" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz" + integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== + +diff-sequences@^29.0.0: + version "29.0.0" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz" + integrity sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +difflib@~0.2.1: + version "0.2.4" + resolved "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz" + integrity sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w== + dependencies: + heap ">= 0.2.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-accessibility-api@^0.5.9: + version "0.5.14" + resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz" + integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg== + +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1, domutils@^3.1.0: + version "3.2.2" + resolved "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz" + integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dreamopt@~0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/dreamopt/-/dreamopt-0.6.0.tgz" + integrity sha512-KRJa47iBEK0y6ZtgCgy2ykuvMT8c9gj3ua9Dv7vCkclFJJeH2FjhGY2xO5qBoWGahsjCGMlk4Cq9wJYeWxuYhQ== + dependencies: + wordwrap ">=0.0.2" + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.5.73: + version "1.5.143" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.143.tgz" + integrity sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g== + +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^10.2.1: + version "10.4.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +encoding-sniffer@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz" + integrity sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg== + dependencies: + iconv-lite "^0.6.3" + whatwg-encoding "^3.1.1" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.15.0: + version "5.18.0" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz" + integrity sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^4.2.0, entities@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +entities@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.9: + version "1.24.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" + integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + +es5-ext@0.8.x: + version "0.8.2" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.8.2.tgz" + integrity sha512-H19ompyhnKiBdjHR1DPHvf5RHgHPmJaY9JNzFGbMbPgdsUkvnUCN1Ke8J4Y0IMyTwFM2M9l4h2GoHwzwpSmXbA== + +esbuild@^0.25.0: + version "0.25.0" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz" + integrity sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.0" + "@esbuild/android-arm" "0.25.0" + "@esbuild/android-arm64" "0.25.0" + "@esbuild/android-x64" "0.25.0" + "@esbuild/darwin-arm64" "0.25.0" + "@esbuild/darwin-x64" "0.25.0" + "@esbuild/freebsd-arm64" "0.25.0" + "@esbuild/freebsd-x64" "0.25.0" + "@esbuild/linux-arm" "0.25.0" + "@esbuild/linux-arm64" "0.25.0" + "@esbuild/linux-ia32" "0.25.0" + "@esbuild/linux-loong64" "0.25.0" + "@esbuild/linux-mips64el" "0.25.0" + "@esbuild/linux-ppc64" "0.25.0" + "@esbuild/linux-riscv64" "0.25.0" + "@esbuild/linux-s390x" "0.25.0" + "@esbuild/linux-x64" "0.25.0" + "@esbuild/netbsd-arm64" "0.25.0" + "@esbuild/netbsd-x64" "0.25.0" + "@esbuild/openbsd-arm64" "0.25.0" + "@esbuild/openbsd-x64" "0.25.0" + "@esbuild/sunos-x64" "0.25.0" + "@esbuild/win32-arm64" "0.25.0" + "@esbuild/win32-ia32" "0.25.0" + "@esbuild/win32-x64" "0.25.0" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0, escodegen@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint-visitor-keys@^3.4.3: + 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== + +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@8.57.0: + version "8.57.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +eslint@^8.57.1: + version "8.57.1" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +eslint@^9.13.0: + version "9.17.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz" + integrity sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.9.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.17.0" + "@eslint/plugin-kit" "^0.2.3" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.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" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@^1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventsource-parser@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz" + integrity sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA== + +eventsource@^3.0.2: + version "3.0.6" + resolved "https://registry.npmjs.org/eventsource/-/eventsource-3.0.6.tgz" + integrity sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA== + dependencies: + eventsource-parser "^3.0.1" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz" + integrity sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw== + dependencies: + homedir-polyfill "^1.0.1" + +expect@^28.0.0, expect@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz" + integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== + dependencies: + "@jest/expect-utils" "^28.1.3" + jest-get-type "^28.0.2" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + +expect@^29.0.0, expect@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz" + integrity sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q== + dependencies: + "@jest/expect-utils" "^29.0.3" + jest-get-type "^29.0.0" + jest-matcher-utils "^29.0.3" + jest-message-util "^29.0.3" + jest-util "^29.0.3" + +expect@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== + dependencies: + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + +expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +expect@^30.0.0: + version "30.0.5" + resolved "https://registry.yarnpkg.com/expect/-/expect-30.0.5.tgz#c23bf193c5e422a742bfd2990ad990811de41a5a" + integrity sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ== + dependencies: + "@jest/expect-utils" "30.0.5" + "@jest/get-type" "30.0.1" + jest-matcher-utils "30.0.5" + jest-message-util "30.0.5" + jest-mock "30.0.5" + jest-util "30.0.5" + +express-rate-limit@^7.5.0: + version "7.5.0" + resolved "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz" + integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg== + +express@^5.0.1: + version "5.1.0" + resolved "https://registry.npmjs.org/express/-/express-5.1.0.tgz" + integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== + dependencies: + accepts "^2.0.0" + body-parser "^2.2.0" + content-disposition "^1.0.0" + content-type "^1.0.5" + cookie "^0.7.1" + cookie-signature "^1.2.1" + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + finalhandler "^2.1.0" + fresh "^2.0.0" + http-errors "^2.0.0" + merge-descriptors "^2.0.0" + mime-types "^3.0.0" + on-finished "^2.4.1" + once "^1.4.0" + parseurl "^1.3.3" + proxy-addr "^2.0.7" + qs "^6.14.0" + range-parser "^1.2.1" + router "^2.2.0" + send "^1.1.0" + serve-static "^2.2.0" + statuses "^2.0.1" + type-is "^2.0.1" + vary "^1.1.2" + +extract-zip@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fb-babel-plugin-utils@^0.13.0: + version "0.13.1" + resolved "https://registry.npmjs.org/fb-babel-plugin-utils/-/fb-babel-plugin-utils-0.13.1.tgz" + integrity sha512-AxAr7ut7v4fzHp5VETGxcDUPmRup5H7bkMNNfxaRunS3jzm2rOS5NLvCPCDnnQIiI6AB0x2GrOx/eIcAOVJAAA== + dependencies: + "@babel/core" "^7.0.0" + "@babel/generator" "^7.0.0" + "@babel/parser" "^7.7.4" + "@babel/plugin-syntax-class-properties" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.7.4" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-syntax-numeric-separator" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.0.0" + json-diff "^0.5.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fbt@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/fbt/-/fbt-1.0.2.tgz" + integrity sha512-vWIasrcX34OW2EWohjrAQM0jpJBH2FjqxW9XrQd38xhtBVXWaks34ePWBSHO3QEShmirRx6kwJNZJrofsHjvlw== + dependencies: + invariant "^2.2.4" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" + +fdir@^6.4.3: + version "6.4.3" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz" + integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz" + integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q== + dependencies: + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + on-finished "^2.4.1" + parseurl "^1.3.3" + statuses "^2.0.1" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-node-modules@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz" + integrity sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg== + dependencies: + findup-sync "^4.0.0" + merge "^2.1.1" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +findup-sync@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz" + integrity sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^4.0.2" + resolve-dir "^1.0.1" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + +flow-enums-runtime@^0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.4.tgz" + integrity sha512-kkJ/ABZb4rhyFw05yCWdcA1K2uW7ddYzz9zVNJp5kRX3BzsIynB4f0E4oLlf+zgDLErj9FwGda1qEAmhnRNXPQ== + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +folder-hash@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/folder-hash/-/folder-hash-4.0.4.tgz" + integrity sha512-zEyYH+UsHEfJJcCRSf9ai5I4CTZwZ8ObONRuEI5hcEmJY5pS0FUWKruX9mMnYJrgC7MlPFDYnGsK1R+WFYjLlQ== + dependencies: + debug "^4.3.3" + minimatch "~5.1.2" + +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +foreground-child@^3.1.1: + version "3.3.0" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz" + integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== + +fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + +get-uri@^6.0.1: + version "6.0.4" + resolved "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz" + integrity sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ== + dependencies: + basic-ftp "^5.0.2" + data-uri-to-buffer "^6.0.2" + debug "^4.3.4" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^10.3.10: + version "10.3.10" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + +glob@^10.4.5: + version "10.4.5" + resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + 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" + +glob@^11.0.0: + version "11.0.1" + resolved "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz" + integrity sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw== + dependencies: + foreground-child "^3.1.0" + jackspeak "^4.0.1" + minimatch "^10.0.0" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz" + integrity sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg== + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.11, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +"heap@>= 0.2.0": + version "0.2.7" + resolved "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz" + integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== + +hermes-eslint@^0.25.1: + version "0.25.1" + resolved "https://registry.npmjs.org/hermes-eslint/-/hermes-eslint-0.25.1.tgz" + integrity sha512-nPz9+oyejT1zsIwoJ2pWdUvLcN1i+tbaWCOD8PpNBYQtnHXaPXImZp/6zZHnm3bo/DoFcAgh8+SNcxLFxh7m/A== + dependencies: + esrecurse "^4.3.0" + hermes-estree "0.25.1" + hermes-parser "0.25.1" + +hermes-estree@0.25.1: + version "0.25.1" + resolved "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz" + integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== + +hermes-estree@0.26.0: + version "0.26.0" + resolved "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.26.0.tgz" + integrity sha512-If1T7lhfXnGlVLbnsmwerNB5cyJm2oIE8TN1UKEq6/OUX1nOGUhjXMpqAwZ1wkkn9Brda0VRyJEWOGT2GgVcAQ== + +hermes-estree@0.32.0: + version "0.32.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.32.0.tgz#bb7da6613ab8e67e334a1854ea1e209f487d307b" + integrity sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ== + +hermes-parser@0.25.1, hermes-parser@^0.25.1: + version "0.25.1" + resolved "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz" + integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA== + dependencies: + hermes-estree "0.25.1" + +hermes-parser@0.26.0: + version "0.26.0" + resolved "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.26.0.tgz" + integrity sha512-fWT40jJ/BtlzuyiiQS7lzNIlB5h6flVZoN8Jn8v5l987HL5dK9s+/4+py0FaBmeIEROC2zxt5qMLwXFTPLQ7BA== + dependencies: + hermes-estree "0.26.0" + +hermes-parser@^0.32.0: + version "0.32.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.32.0.tgz#7916984ef6fdce62e7415d354cf35392061cd303" + integrity sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw== + dependencies: + hermes-estree "0.32.0" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== + dependencies: + whatwg-encoding "^2.0.0" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-to-text@^9.0.5: + version "9.0.5" + resolved "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz" + integrity sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg== + dependencies: + "@selderee/plugin-htmlparser2" "^0.11.0" + deepmerge "^4.3.1" + dom-serializer "^2.0.0" + htmlparser2 "^8.0.2" + selderee "^0.11.0" + +htmlparser2@^8.0.2: + version "8.0.2" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz" + integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + entities "^4.4.0" + +htmlparser2@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz" + integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.1.0" + entities "^4.5.0" + +http-errors@2.0.0, http-errors@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1, http-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +https-proxy-agent@^7.0.5, https-proxy-agent@^7.0.6: + version "7.0.6" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.6.3, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +ignore@^5.2.4: + version "5.3.1" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +import-fresh@^3.2.1, import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== + dependencies: + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-generator-function@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== + dependencies: + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-unicode-supported@^1.1.0, is-unicode-supported@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz" + integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== + dependencies: + call-bound "^1.0.3" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +is-windows@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +istanbul-reports@^3.1.6: + version "3.1.7" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jackspeak@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz" + integrity sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw== + dependencies: + "@isaacs/cliui" "^8.0.2" + +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + +jest-changed-files@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz" + integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-changed-files@^29.0.0: + version "29.0.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz" + integrity sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz" + integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + p-limit "^3.1.0" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-circus@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz" + integrity sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg== + dependencies: + "@jest/environment" "^29.0.3" + "@jest/expect" "^29.0.3" + "@jest/test-result" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^29.0.3" + jest-matcher-utils "^29.0.3" + jest-message-util "^29.0.3" + jest-runtime "^29.0.3" + jest-snapshot "^29.0.3" + jest-util "^29.0.3" + p-limit "^3.1.0" + pretty-format "^29.0.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-circus@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz" + integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^29.5.0" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + p-limit "^3.1.0" + pretty-format "^29.5.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz" + integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== + dependencies: + "@jest/core" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-cli@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz" + integrity sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ== + dependencies: + "@jest/core" "^29.0.3" + "@jest/test-result" "^29.0.3" + "@jest/types" "^29.0.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.0.3" + jest-util "^29.0.3" + jest-validate "^29.0.3" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-cli@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz" + integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== + dependencies: + "@jest/core" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz" + integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.3" + "@jest/types" "^28.1.3" + babel-jest "^28.1.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^28.1.3" + jest-environment-node "^28.1.3" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-runner "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^28.1.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-config@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz" + integrity sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.0.3" + "@jest/types" "^29.0.3" + babel-jest "^29.0.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.0.3" + jest-environment-node "^29.0.3" + jest-get-type "^29.0.0" + jest-regex-util "^29.0.0" + jest-resolve "^29.0.3" + jest-runner "^29.0.3" + jest-util "^29.0.3" + jest-validate "^29.0.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.0.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-config@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz" + integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.5.0" + "@jest/types" "^29.5.0" + babel-jest "^29.5.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.5.0" + jest-environment-node "^29.5.0" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-runner "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.5.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.0.5.tgz#b40f81e0c0d13e5b81c4d62b0d0dfa6a524ee0fd" + integrity sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A== + dependencies: + "@jest/diff-sequences" "30.0.1" + "@jest/get-type" "30.0.1" + chalk "^4.1.2" + pretty-format "30.0.5" + +jest-diff@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz" + integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== + dependencies: + chalk "^4.0.0" + diff-sequences "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-diff@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz" + integrity sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.0.0" + jest-get-type "^29.0.0" + pretty-format "^29.0.3" + +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== + dependencies: + detect-newline "^3.0.0" + +jest-docblock@^28.1.1: + version "28.1.1" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== + dependencies: + detect-newline "^3.0.0" + +jest-docblock@^29.0.0: + version "29.0.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz" + integrity sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw== + dependencies: + detect-newline "^3.0.0" + +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz" + integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== + dependencies: + "@jest/types" "^28.1.3" + chalk "^4.0.0" + jest-get-type "^28.0.2" + jest-util "^28.1.3" + pretty-format "^28.1.3" + +jest-each@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz" + integrity sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg== + dependencies: + "@jest/types" "^29.0.3" + chalk "^4.0.0" + jest-get-type "^29.0.0" + jest-util "^29.0.3" + pretty-format "^29.0.3" + +jest-each@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz" + integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== + dependencies: + "@jest/types" "^29.5.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.5.0" + pretty-format "^29.5.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-jsdom@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.0.3.tgz" + integrity sha512-KIGvpm12c71hoYTjL4wC2c8K6KfhOHJqJtaHc1IApu5rG047YWZoEP13BlbucWfzGISBrmli8KFqdhdQEa8Wnw== + dependencies: + "@jest/environment" "^29.0.3" + "@jest/fake-timers" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/jsdom" "^20.0.0" + "@types/node" "*" + jest-mock "^29.0.3" + jest-util "^29.0.3" + jsdom "^20.0.0" + +jest-environment-node@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz" + integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +jest-environment-node@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz" + integrity sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg== + dependencies: + "@jest/environment" "^29.0.3" + "@jest/fake-timers" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/node" "*" + jest-mock "^29.0.3" + jest-util "^29.0.3" + +jest-environment-node@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz" + integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-mock "^29.5.0" + jest-util "^29.5.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^28.0.2: + version "28.0.2" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz" + integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== + +jest-get-type@^29.0.0: + version "29.0.0" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz" + integrity sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw== + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz" + integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== + dependencies: + "@jest/types" "^28.1.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + jest-worker "^28.1.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-haste-map@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz" + integrity sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A== + dependencies: + "@jest/types" "^29.0.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.0.0" + jest-util "^29.0.3" + jest-worker "^29.0.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-haste-map@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz" + integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== + dependencies: + "@jest/types" "^29.5.0" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + jest-worker "^29.5.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz" + integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== + dependencies: + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-leak-detector@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz" + integrity sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ== + dependencies: + jest-get-type "^29.0.0" + pretty-format "^29.0.3" + +jest-leak-detector@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz" + integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz#dff3334be58faea4a5e1becc228656fbbfc2467d" + integrity sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ== + dependencies: + "@jest/get-type" "30.0.1" + chalk "^4.1.2" + jest-diff "30.0.5" + pretty-format "30.0.5" + +jest-matcher-utils@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz" + integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== + dependencies: + chalk "^4.0.0" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-matcher-utils@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz" + integrity sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w== + dependencies: + chalk "^4.0.0" + jest-diff "^29.0.3" + jest-get-type "^29.0.0" + pretty-format "^29.0.3" + +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== + dependencies: + chalk "^4.0.0" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.0.5.tgz#dd12ffec91dd3fa6a59cbd538a513d8e239e070c" + integrity sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA== + dependencies: + "@babel/code-frame" "^7.27.1" + "@jest/types" "30.0.5" + "@types/stack-utils" "^2.0.3" + chalk "^4.1.2" + graceful-fs "^4.2.11" + micromatch "^4.0.8" + pretty-format "30.0.5" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-message-util@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz" + integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^28.1.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz" + integrity sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.0.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.0.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.5.0" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.5.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.0.5.tgz#ef437e89212560dd395198115550085038570bdd" + integrity sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + jest-util "30.0.5" + +jest-mock@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz" + integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + +jest-mock@^29.0.3, jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-mock@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz" + integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-util "^29.5.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-30.0.1.tgz#f17c1de3958b67dfe485354f5a10093298f2a49b" + integrity sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA== + +jest-regex-util@^28.0.2: + version "28.0.2" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + +jest-regex-util@^29.0.0: + version "29.0.0" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz" + integrity sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz" + integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== + dependencies: + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.3" + +jest-resolve-dependencies@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz" + integrity sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw== + dependencies: + jest-regex-util "^29.0.0" + jest-snapshot "^29.0.3" + +jest-resolve-dependencies@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz" + integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.5.0" + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz" + integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-pnp-resolver "^1.2.2" + jest-util "^28.1.3" + jest-validate "^28.1.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-resolve@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz" + integrity sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.0.3" + jest-pnp-resolver "^1.2.2" + jest-util "^29.0.3" + jest-validate "^29.0.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-resolve@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz" + integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.5.0" + jest-validate "^29.5.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz" + integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/environment" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.3" + jest-haste-map "^28.1.3" + jest-leak-detector "^28.1.3" + jest-message-util "^28.1.3" + jest-resolve "^28.1.3" + jest-runtime "^28.1.3" + jest-util "^28.1.3" + jest-watcher "^28.1.3" + jest-worker "^28.1.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runner@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz" + integrity sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw== + dependencies: + "@jest/console" "^29.0.3" + "@jest/environment" "^29.0.3" + "@jest/test-result" "^29.0.3" + "@jest/transform" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^29.0.0" + jest-environment-node "^29.0.3" + jest-haste-map "^29.0.3" + jest-leak-detector "^29.0.3" + jest-message-util "^29.0.3" + jest-resolve "^29.0.3" + jest-runtime "^29.0.3" + jest-util "^29.0.3" + jest-watcher "^29.0.3" + jest-worker "^29.0.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runner@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz" + integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== + dependencies: + "@jest/console" "^29.5.0" + "@jest/environment" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.5.0" + jest-haste-map "^29.5.0" + jest-leak-detector "^29.5.0" + jest-message-util "^29.5.0" + jest-resolve "^29.5.0" + jest-runtime "^29.5.0" + jest-util "^29.5.0" + jest-watcher "^29.5.0" + jest-worker "^29.5.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz" + integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/globals" "^28.1.3" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-runtime@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz" + integrity sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ== + dependencies: + "@jest/environment" "^29.0.3" + "@jest/fake-timers" "^29.0.3" + "@jest/globals" "^29.0.3" + "@jest/source-map" "^29.0.0" + "@jest/test-result" "^29.0.3" + "@jest/transform" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.0.3" + jest-message-util "^29.0.3" + jest-mock "^29.0.3" + jest-regex-util "^29.0.0" + jest-resolve "^29.0.3" + jest-snapshot "^29.0.3" + jest-util "^29.0.3" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-runtime@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz" + integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/globals" "^29.5.0" + "@jest/source-map" "^29.4.3" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz" + integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^28.1.3" + graceful-fs "^4.2.9" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + natural-compare "^1.4.0" + pretty-format "^28.1.3" + semver "^7.3.5" + +jest-snapshot@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz" + integrity sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.0.3" + "@jest/transform" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.0.3" + graceful-fs "^4.2.9" + jest-diff "^29.0.3" + jest-get-type "^29.0.0" + jest-haste-map "^29.0.3" + jest-matcher-utils "^29.0.3" + jest-message-util "^29.0.3" + jest-util "^29.0.3" + natural-compare "^1.4.0" + pretty-format "^29.0.3" + semver "^7.3.5" + +jest-snapshot@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz" + integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.5.0" + graceful-fs "^4.2.9" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + natural-compare "^1.4.0" + pretty-format "^29.5.0" + semver "^7.3.5" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.0.5.tgz#035d380c660ad5f1748dff71c4105338e05f8669" + integrity sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + ci-info "^4.2.0" + graceful-fs "^4.2.11" + picomatch "^4.0.2" + +jest-util@^28.0.0, jest-util@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz" + integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^29.0.0, jest-util@^29.0.3, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz" + integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== + dependencies: + "@jest/types" "^28.1.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^28.0.2" + leven "^3.1.0" + pretty-format "^28.1.3" + +jest-validate@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz" + integrity sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw== + dependencies: + "@jest/types" "^29.0.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.0.0" + leven "^3.1.0" + pretty-format "^29.0.3" + +jest-validate@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz" + integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== + dependencies: + "@jest/types" "^29.5.0" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.5.0" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + +jest-watcher@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz" + integrity sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw== + dependencies: + "@jest/test-result" "^29.0.3" + "@jest/types" "^29.0.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^29.0.3" + string-length "^4.0.1" + +jest-watcher@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz" + integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== + dependencies: + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.5.0" + string-length "^4.0.1" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz" + integrity sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz" + integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== + dependencies: + "@types/node" "*" + jest-util "^29.5.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz" + integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== + dependencies: + "@jest/core" "^28.1.3" + "@jest/types" "^28.1.3" + import-local "^3.0.2" + jest-cli "^28.1.3" + +jest@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz" + integrity sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ== + dependencies: + "@jest/core" "^29.0.3" + "@jest/types" "^29.0.3" + import-local "^3.0.2" + jest-cli "^29.0.3" + +jest@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz" + integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== + dependencies: + "@jest/core" "^29.5.0" + "@jest/types" "^29.5.0" + import-local "^3.0.2" + jest-cli "^29.5.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +joi@^17.11.0: + version "17.13.1" + resolved "https://registry.npmjs.org/joi/-/joi-17.13.1.tgz" + integrity sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg== + dependencies: + "@hapi/hoek" "^9.3.0" + "@hapi/topo" "^5.1.0" + "@sideway/address" "^4.1.5" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + +jsdom@^20.0.0: + version "20.0.0" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-20.0.0.tgz" + integrity sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA== + dependencies: + abab "^2.0.6" + acorn "^8.7.1" + acorn-globals "^6.0.0" + cssom "^0.5.0" + cssstyle "^2.3.0" + data-urls "^3.0.2" + decimal.js "^10.3.1" + domexception "^4.0.0" + escodegen "^2.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "^7.0.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + ws "^8.8.0" + xml-name-validator "^4.0.0" + +jsdom@^22.1.0: + version "22.1.0" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz" + integrity sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw== + dependencies: + abab "^2.0.6" + cssstyle "^3.0.0" + data-urls "^4.0.0" + decimal.js "^10.4.3" + domexception "^4.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.4" + parse5 "^7.1.2" + rrweb-cssom "^0.6.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.2" + w3c-xmlserializer "^4.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^12.0.1" + ws "^8.13.0" + xml-name-validator "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +jsesc@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-diff@^0.5.4: + version "0.5.5" + resolved "https://registry.npmjs.org/json-diff/-/json-diff-0.5.5.tgz" + integrity sha512-B2RSfPv8Y5iqm6/9aKC3cOhXPzjYupKDpGuqT5py9NRulL8J0UoB/zKXUo70xBsuxPcIFgtsGgEdXLrNp0GL7w== + dependencies: + cli-color "~0.1.6" + difflib "~0.2.1" + dreamopt "~0.6.0" + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + 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== + +json-stable-stringify-without-jsonify@^1.0.1: + 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== + +json5@^2.1.0, json5@^2.2.1, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + +keypress@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz" + integrity sha512-HjorDJFNhnM4SicvaUXac0X77NiskggxJdesG72+O5zBKpSqKFCrqmndKVqpu3pFqkla0St6uGk8Ju0sCurrmg== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +leac@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz" + integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg== + +leven@2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz" + integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +lilconfig@^3.1.1: + version "3.1.3" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@4.x, lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + +lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-symbols@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz" + integrity sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA== + dependencies: + chalk "^5.0.0" + is-unicode-supported "^1.1.0" + +logform@^2.6.0, logform@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz" + integrity sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^11.0.0: + version "11.1.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz" + integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +"lru-cache@^9.1.1 || ^10.0.0": + version "10.2.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + +lz-string@^1.4.4: + version "1.4.4" + resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz" + integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@1.x, make-error@^1.1.1, make-error@^1.3.6: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +media-typer@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz" + integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + +merge-descriptors@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz" + integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +merge@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz" + integrity sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w== + +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime-types@^3.0.0, mime-types@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz" + integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA== + dependencies: + mime-db "^1.54.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@9.0.3, minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^10.0.0: + version "10.0.1" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1, minimatch@^5.1.6, minimatch@~5.1.2: + version "5.1.6" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +mitt@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== + +mkdirp@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +mocha@^10.2.0: + version "10.8.2" + resolved "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz" + integrity sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +mocha@^11.0.1: + version "11.0.1" + resolved "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz" + integrity sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^10.4.5" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +mri@1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz" + integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +native-or-another@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/native-or-another/-/native-or-another-2.0.0.tgz" + integrity sha512-rDE50rrX/PSk2StV5EnwpRk35TENl4I4ZsSGZsMJufLdAJ1P4YzNwVf5UOhjQodwz+RdTP9eZSG7FiqnoY25nA== + dependencies: + native-or-bluebird "^1.1.2" + +native-or-bluebird@^1.1.2: + version "1.2.0" + resolved "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz" + integrity sha512-0SH8UubxDfe382eYiwmd12qxAbiWGzlGZv6CkMA+DPojWa/Y0oH4hE0lRtFfFgJmPQFyKXeB8XxPbZz6TvvKaQ== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== + +netmask@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + +node-addon-api@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-dts@^1.3.13: + version "1.3.13" + resolved "https://registry.npmjs.org/npm-dts/-/npm-dts-1.3.13.tgz" + integrity sha512-k1G0x0aIN8Wc0KyEZe2zAvBQqPi2NMBTg0fanEUhmBkynvb/KLy+J8F3ozyPGW1sAdnjaSHfCe1hd/X/IaD4Fw== + dependencies: + args "5.0.3" + find-node-modules "2.1.3" + mkdirp "3.0.1" + npm-run "5.0.1" + rimraf "6.0.1" + tmp "0.2.3" + winston "3.13.1" + +npm-path@^2.0.2, npm-path@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz" + integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== + dependencies: + which "^1.2.10" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/npm-run/-/npm-run-5.0.1.tgz" + integrity sha512-s7FyRpHUgaJfzkRgOnevX8rAWWsv1dofY1XS7hliWCF6LSQh+HtDfBvpigPS1krLvXw+Fi17CYMY8mUtblnyWw== + dependencies: + minimist "^1.2.0" + npm-path "^2.0.4" + npm-which "^3.0.1" + serializerr "^1.0.3" + +npm-which@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz" + integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== + dependencies: + commander "^2.9.0" + npm-path "^2.0.2" + which "^1.2.10" + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + +nwsapi@^2.2.0: + version "2.2.2" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz" + integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== + +nwsapi@^2.2.4: + version "2.2.7" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz" + integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +on-finished@^2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +ora@5.4.1: + version "5.4.1" + resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +ora@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz" + integrity sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw== + dependencies: + chalk "^5.3.0" + cli-cursor "^4.0.0" + cli-spinners "^2.9.0" + is-interactive "^2.0.0" + is-unicode-supported "^1.3.0" + log-symbols "^5.1.0" + stdin-discarder "^0.1.0" + string-width "^6.1.0" + strip-ansi "^7.1.0" + +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + 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== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pac-proxy-agent@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz" + integrity sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA== + dependencies: + "@tootallnate/quickjs-emscripten" "^0.23.0" + agent-base "^7.1.2" + debug "^4.3.4" + get-uri "^6.0.1" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.6" + pac-resolver "^7.0.1" + socks-proxy-agent "^8.0.5" + +pac-resolver@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz" + integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg== + dependencies: + degenerator "^5.0.0" + netmask "^2.0.2" + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz" + integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== + +parse5-htmlparser2-tree-adapter@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz" + integrity sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g== + dependencies: + domhandler "^5.0.3" + parse5 "^7.0.0" + +parse5-parser-stream@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz" + integrity sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow== + dependencies: + parse5 "^7.0.0" + +parse5@^7.0.0: + version "7.1.1" + resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz" + integrity sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg== + dependencies: + entities "^4.4.0" + +parse5@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + +parseley@^0.12.0: + version "0.12.1" + resolved "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz" + integrity sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw== + dependencies: + leac "^0.6.0" + peberminta "^0.9.0" + +parseurl@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== + dependencies: + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + +path-to-regexp@^8.0.0: + version "8.2.0" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz" + integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +peberminta@^0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz" + integrity sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ== + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.1: + version "4.0.6" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pirates@^4.0.4, pirates@^4.0.5: + version "4.0.5" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkce-challenge@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz" + integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ== + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +postcss-load-config@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz" + integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== + dependencies: + lilconfig "^3.1.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-plugin-hermes-parser@0.26.0, prettier-plugin-hermes-parser@^0.26.0: + version "0.26.0" + resolved "https://registry.npmjs.org/prettier-plugin-hermes-parser/-/prettier-plugin-hermes-parser-0.26.0.tgz" + integrity sha512-ajjlx/0OQ+lcZQEnKEUDU7Srr9vw1OoMO6qZDIYmck1u7j9STiCStqb3RG1vE7FripXYAhquuI+oYG8BCTNC4g== + dependencies: + hermes-estree "0.26.0" + hermes-parser "0.26.0" + prettier-plugin-hermes-parser "0.26.0" + +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + +pretty-format@30.0.5, pretty-format@^30.0.0: + version "30.0.5" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.0.5.tgz#e001649d472800396c1209684483e18a4d250360" + integrity sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw== + dependencies: + "@jest/schemas" "30.0.5" + ansi-styles "^5.2.0" + react-is "^18.3.1" + +pretty-format@^24: + version "24.9.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + +pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^28.0.0, pretty-format@^28.1.3: + version "28.1.3" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz" + integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== + dependencies: + "@jest/schemas" "^28.1.3" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.0.3: + version "29.0.3" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz" + integrity sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== + dependencies: + "@jest/schemas" "^29.4.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prompt-promise@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/prompt-promise/-/prompt-promise-1.0.3.tgz" + integrity sha512-xIbGSzK59hFiwn9kmD0Cki4igpUqTVx7c6D8lqZoENAZyTwxhMhh/QleHWoRFVVusi7CTj/ByHP3N+2EmkhKIA== + dependencies: + keypress "~0.2.1" + native-or-another "~2.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +protochain@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/protochain/-/protochain-1.0.5.tgz" + integrity sha512-4hDwFSX50C4NE6f/6zg8EPr/WLPTkFPUtG0ulWZu6bwzV2hmb50fpdQLr0HiKBAUehapaFpItzWoCLjraLJhUA== + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-agent@^6.5.0: + version "6.5.0" + resolved "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz" + integrity sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A== + dependencies: + agent-base "^7.1.2" + debug "^4.3.4" + http-proxy-agent "^7.0.1" + https-proxy-agent "^7.0.6" + lru-cache "^7.14.1" + pac-proxy-agent "^7.1.0" + proxy-from-env "^1.1.0" + socks-proxy-agent "^8.0.5" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +pump@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +punycode@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +puppeteer-core@24.7.2: + version "24.7.2" + resolved "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.7.2.tgz" + integrity sha512-P9pZyTmJqKODFCnkZgemCpoFA4LbAa8+NumHVQKyP5X9IgdNS1ZnAnIh1sMAwhF8/xEUGf7jt+qmNLlKieFw1Q== + dependencies: + "@puppeteer/browsers" "2.10.2" + chromium-bidi "4.1.1" + debug "^4.4.0" + devtools-protocol "0.0.1425554" + typed-query-selector "^2.12.0" + ws "^8.18.1" + +puppeteer@^24.7.2: + version "24.7.2" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-24.7.2.tgz" + integrity sha512-ifYqoY6wGs0yZeFuFPn8BE9FhuveXkarF+eO18I2e/axdoCh4Qh1AE+qXdJBhdaeoPt6eRNTY4Dih29Jbq8wow== + dependencies: + "@puppeteer/browsers" "2.10.2" + chromium-bidi "4.1.1" + cosmiconfig "^9.0.0" + devtools-protocol "0.0.1425554" + puppeteer-core "24.7.2" + typed-query-selector "^2.12.0" + +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + +qs@^6.14.0: + version "6.14.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz" + integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.6.3" + unpipe "1.0.0" + +react-dom@0.0.0-experimental-4beb1fd8-20241118: + version "0.0.0-experimental-4beb1fd8-20241118" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-0.0.0-experimental-4beb1fd8-20241118.tgz" + integrity sha512-/Gs2N/6hiuwqf2uuJ3UN/PWxpIncbuY7XY/IynlB2oNpopeV+x1MMXfNdse8TiPkpgg9aw+VUfQUlLPC52bKiQ== + dependencies: + scheduler "0.0.0-experimental-4beb1fd8-20241118" + +react-is@0.0.0-experimental-4beb1fd8-20241118: + version "0.0.0-experimental-4beb1fd8-20241118" + resolved "https://registry.npmjs.org/react-is/-/react-is-0.0.0-experimental-4beb1fd8-20241118.tgz" + integrity sha512-7JE3PtW4zpMYdp1bTXKNmz2t0jzaqc3frMWbvbuZmhif5ndtYx5oCGhfnbm6S5ZeTNKe4GXsN5D73QtZClfepQ== + +react-is@^16.8.4: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0, react-is@^18.3.1: + version "18.3.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +react@0.0.0-experimental-4beb1fd8-20241118: + version "0.0.0-experimental-4beb1fd8-20241118" + resolved "https://registry.npmjs.org/react/-/react-0.0.0-experimental-4beb1fd8-20241118.tgz" + integrity sha512-SojDx9IQZXRbze+BNoLRiBDblVTMRebpOZyU2QyRk4ptJob78QiROi58uuE7yxrFMDQN4kBl6tqYkSwQaIM2nQ== + +readable-stream@^3.4.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +readline@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz" + integrity sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg== + +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regenerate-unicode-properties@^10.2.0: + version "10.2.0" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz" + integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexp.escape@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexp.escape/-/regexp.escape-2.0.1.tgz#09e4beef9d202dbd739868f3818223f977cf91da" + integrity sha512-JItRb4rmyTzmERBkAf6J87LjDPy/RscIwmaJQ3gsFlAzrmZbZU8LwBw5IydFZXW9hqpgbPlGbMhtpqtuAhMgtg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + for-each "^0.3.3" + safe-regex-test "^1.0.3" + +regexp.prototype.flags@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" + +regexpu-core@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz" + integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.0" + regjsgen "^0.8.0" + regjsparser "^0.12.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz" + integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== + dependencies: + jsesc "~3.0.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz" + integrity sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg== + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.14.2, resolve@^1.20.0, resolve@^1.3.2: + version "1.22.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@6.0.1, rimraf@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz" + integrity sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A== + dependencies: + glob "^11.0.0" + package-json-from-dist "^1.0.0" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^4.34.8: + version "4.34.9" + resolved "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz" + integrity sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.34.9" + "@rollup/rollup-android-arm64" "4.34.9" + "@rollup/rollup-darwin-arm64" "4.34.9" + "@rollup/rollup-darwin-x64" "4.34.9" + "@rollup/rollup-freebsd-arm64" "4.34.9" + "@rollup/rollup-freebsd-x64" "4.34.9" + "@rollup/rollup-linux-arm-gnueabihf" "4.34.9" + "@rollup/rollup-linux-arm-musleabihf" "4.34.9" + "@rollup/rollup-linux-arm64-gnu" "4.34.9" + "@rollup/rollup-linux-arm64-musl" "4.34.9" + "@rollup/rollup-linux-loongarch64-gnu" "4.34.9" + "@rollup/rollup-linux-powerpc64le-gnu" "4.34.9" + "@rollup/rollup-linux-riscv64-gnu" "4.34.9" + "@rollup/rollup-linux-s390x-gnu" "4.34.9" + "@rollup/rollup-linux-x64-gnu" "4.34.9" + "@rollup/rollup-linux-x64-musl" "4.34.9" + "@rollup/rollup-win32-arm64-msvc" "4.34.9" + "@rollup/rollup-win32-ia32-msvc" "4.34.9" + "@rollup/rollup-win32-x64-msvc" "4.34.9" + fsevents "~2.3.2" + +router@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/router/-/router-2.2.0.tgz" + integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== + dependencies: + debug "^4.4.0" + depd "^2.0.0" + is-promise "^4.0.0" + parseurl "^1.3.3" + path-to-regexp "^8.0.0" + +rrweb-cssom@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz" + integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.0.0, rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + +safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + +scheduler@0.0.0-experimental-4beb1fd8-20241118: + version "0.0.0-experimental-4beb1fd8-20241118" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.0.0-experimental-4beb1fd8-20241118.tgz" + integrity sha512-b7GQktevD5BPcS+R5qY5se5oX4b8AHQyebWswGZBdLCmElIwR3Q+RO5EgsLOA4t5D3/TDjLm58CQG16uEB5rMA== + +selderee@^0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz" + integrity sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA== + dependencies: + parseley "^0.12.0" + +semver@7.x, semver@^7.3.5: + version "7.3.7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^5.4.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +semver@^7.6.0, semver@^7.6.2: + version "7.6.3" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +semver@^7.7.1: + version "7.7.1" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +send@^1.1.0, send@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/send/-/send-1.2.0.tgz" + integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw== + dependencies: + debug "^4.3.5" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + fresh "^2.0.0" + http-errors "^2.0.0" + mime-types "^3.0.1" + ms "^2.1.3" + on-finished "^2.4.1" + range-parser "^1.2.1" + statuses "^2.0.1" + +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +serializerr@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/serializerr/-/serializerr-1.0.3.tgz" + integrity sha512-yXUlHj0fjbndhACj2XWtIH5eJv7b/uadyl7CJA8b9wL5mIKm+g0/sL7rDzEmjC+k5y8ggcaP8i049F4FxA0U9Q== + dependencies: + protochain "^1.0.5" + +serve-static@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz" + integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ== + dependencies: + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.8.1" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@^8.0.5: + version "8.0.5" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz" + integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== + dependencies: + agent-base "^7.1.2" + debug "^4.3.4" + socks "^2.8.3" + +socks@^2.8.3: + version "2.8.4" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz" + integrity sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.16: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spawn-command@^0.0.2-1: + version "0.0.2-1" + resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz" + integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== + +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +stack-utils@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@2.0.1, statuses@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +stdin-discarder@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz" + integrity sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ== + dependencies: + bl "^5.0.0" + +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== + dependencies: + es-errors "^1.3.0" + internal-slot "^1.1.0" + +streamx@^2.15.0, streamx@^2.21.0: + version "2.22.0" + resolved "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz" + integrity sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw== + dependencies: + fast-fifo "^1.3.2" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string-width@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz" + integrity sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^10.2.1" + strip-ansi "^7.0.1" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1, strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +sucrase@^3.35.0: + version "3.35.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0, supports-color@^8.1.0, supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^9.4.0: + version "9.4.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz" + integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== + +supports-hyperlinks@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +tar-fs@^3.0.8: + version "3.0.8" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz" + integrity sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg== + dependencies: + pump "^3.0.0" + tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^4.0.1" + bare-path "^3.0.0" + +tar-stream@^3.1.5: + version "3.1.7" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-decoder@^1.1.0: + version "1.2.3" + resolved "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz" + integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA== + dependencies: + b4a "^1.6.4" + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.11: + version "0.2.12" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz" + integrity sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww== + dependencies: + fdir "^6.4.3" + picomatch "^4.0.2" + +tmp@0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tough-cookie@^4.0.0, tough-cookie@^4.1.2: + version "4.1.4" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz" + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== + dependencies: + punycode "^2.1.0" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + +tr46@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz" + integrity sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw== + dependencies: + punycode "^2.3.0" + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz" + integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== + +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +ts-jest@^28.0.7: + version "28.0.8" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz" + integrity sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + +ts-jest@^29.1.1: + version "29.1.1" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +ts-jest@^29.3.2: + version "29.3.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.3.2.tgz#0576cdf0a507f811fe73dcd16d135ce89f8156cb" + integrity sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug== + dependencies: + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.1" + type-fest "^4.39.1" + yargs-parser "^21.1.1" + +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^2.0.1, tslib@^2.1.0: + version "2.5.2" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz" + integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA== + +tsup@^8.4.0: + version "8.4.0" + resolved "https://registry.npmjs.org/tsup/-/tsup-8.4.0.tgz" + integrity sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ== + dependencies: + bundle-require "^5.1.0" + cac "^6.7.14" + chokidar "^4.0.3" + consola "^3.4.0" + debug "^4.4.0" + esbuild "^0.25.0" + joycon "^3.1.1" + picocolors "^1.1.1" + postcss-load-config "^6.0.1" + resolve-from "^5.0.0" + rollup "^4.34.8" + source-map "0.8.0-beta.0" + sucrase "^3.35.0" + tinyexec "^0.3.2" + tinyglobby "^0.2.11" + tree-kill "^1.2.2" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^4.39.1: + version "4.40.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.40.1.tgz#d78a09f08dd1081a434dd377967650cfd565401d" + integrity sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA== + +type-is@^2.0.0, type-is@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz" + integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== + dependencies: + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + +typed-query-selector@^2.12.0: + version "2.12.0" + resolved "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz" + integrity sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg== + +typescript-eslint@^8.16.0: + version "8.18.1" + resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.1.tgz" + integrity sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.18.1" + "@typescript-eslint/parser" "8.18.1" + "@typescript-eslint/utils" "8.18.1" + +typescript@^5.0.0: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +typescript@^5.4.3: + version "5.4.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz" + integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== + +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +undici@^6.19.5: + version "6.23.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.23.0.tgz#7953087744d9095a96f115de3140ca3828aff3a4" + integrity sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz" + integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.1.1: + version "1.1.3" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.0: + version "9.3.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +vary@^1, vary@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz" + integrity sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg== + dependencies: + xml-name-validator "^4.0.0" + +w3c-xmlserializer@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz" + integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== + dependencies: + xml-name-validator "^4.0.0" + +wait-on@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz" + integrity sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ== + dependencies: + axios "^1.6.1" + joi "^17.11.0" + lodash "^4.17.21" + minimist "^1.2.8" + rxjs "^7.8.1" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== + dependencies: + iconv-lite "0.6.3" + +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +whatwg-url@^12.0.0, whatwg-url@^12.0.1: + version "12.0.1" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz" + integrity sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ== + dependencies: + tr46 "^4.1.1" + webidl-conversions "^7.0.0" + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" + integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + +which-typed-array@^1.1.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^1.2.10, which@^1.2.14: + version "1.3.1" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +winston-transport@^4.7.0: + version "4.9.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz" + integrity sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A== + dependencies: + logform "^2.7.0" + readable-stream "^3.6.2" + triple-beam "^1.3.0" + +winston@3.13.1: + version "3.13.1" + resolved "https://registry.npmjs.org/winston/-/winston-3.13.1.tgz" + integrity sha512-SvZit7VFNvXRzbqGHsv5KSmgbEYR5EiQfDAL9gxYkRqa934Hnk++zze0wANKtMHcy/gI4W/3xmSDwlhf865WGw== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.6.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + +wordwrap@>=0.0.2: + version "1.0.0" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +ws@^8.13.0, ws@^8.18.1, ws@^8.8.0: + version "8.18.1" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== + +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.3.1, yargs@^17.7.1, yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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" + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod-to-json-schema@^3.24.1: + version "3.24.5" + resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz" + integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g== + +"zod-validation-error@^3.5.0 || ^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918" + integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== + +zod@^3.23.8, zod@^3.24.1: + version "3.24.3" + resolved "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz" + integrity sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg== + +"zod@^3.25.0 || ^4.0.0": + version "4.1.12" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.12.tgz#64f1ea53d00eab91853195653b5af9eee68970f0" + integrity sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ== diff --git a/dangerfile.js b/dangerfile.js index 86e7e422a5b4..b7ee95d75f88 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -7,6 +7,8 @@ 'use strict'; +/* eslint-disable no-for-of-loops/no-for-of-loops */ + // Hi, if this is your first time editing/reading a Dangerfile, here's a summary: // It's a JS runtime which helps you provide continuous feedback inside GitHub. // @@ -26,270 +28,255 @@ // `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865 const {markdown, danger, warn} = require('danger'); -const fetch = require('node-fetch'); - -const {generateResultsArray} = require('./scripts/rollup/stats'); -const {existsSync, readFileSync} = require('fs'); -const {exec} = require('child_process'); - -// This must match the name of the CI job that creates the build artifacts -const RELEASE_CHANNEL = - process.env.RELEASE_CHANNEL === 'experimental' ? 'experimental' : 'stable'; -const artifactsJobName = - process.env.RELEASE_CHANNEL === 'experimental' - ? 'process_artifacts_experimental' - : 'process_artifacts'; - -if (!existsSync('./build/bundle-sizes.json')) { - // This indicates the build failed previously. - // In that case, there's nothing for the Dangerfile to do. - // Exit early to avoid leaving a redundant (and potentially confusing) PR comment. - warn( - 'No bundle size information found. This indicates the build ' + - 'job failed.' - ); - process.exit(0); +const {promisify} = require('util'); +const glob = promisify(require('glob')); +const gzipSize = require('gzip-size'); +const {writeFileSync} = require('fs'); + +const {readFileSync, statSync} = require('fs'); + +const BASE_DIR = 'base-build'; +const HEAD_DIR = 'build'; + +const CRITICAL_THRESHOLD = 0.02; +const SIGNIFICANCE_THRESHOLD = 0.002; +const CRITICAL_ARTIFACT_PATHS = new Set([ + // We always report changes to these bundles, even if the change is + // insignificant or non-existent. + 'oss-stable/react-dom/cjs/react-dom.production.js', + 'oss-stable/react-dom/cjs/react-dom-client.production.js', + 'oss-experimental/react-dom/cjs/react-dom.production.js', + 'oss-experimental/react-dom/cjs/react-dom-client.production.js', + 'facebook-www/ReactDOM-prod.classic.js', + 'facebook-www/ReactDOM-prod.modern.js', +]); + +const kilobyteFormatter = new Intl.NumberFormat('en', { + style: 'unit', + unit: 'kilobyte', + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); + +function kbs(bytes) { + return kilobyteFormatter.format(bytes / 1000); } -const currentBuildResults = JSON.parse( - readFileSync('./build/bundle-sizes.json') -); - -/** - * Generates a Markdown table - * @param {string[]} headers - * @param {string[][]} body - */ -function generateMDTable(headers, body) { - const tableHeaders = [ - headers.join(' | '), - headers.map(() => ' --- ').join(' | '), - ]; +const percentFormatter = new Intl.NumberFormat('en', { + style: 'percent', + signDisplay: 'exceptZero', + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); - const tablebody = body.map(r => r.join(' | ')); - return tableHeaders.join('\n') + '\n' + tablebody.join('\n'); -} - -/** - * Generates a user-readable string from a percentage change - * @param {number} change - * @param {boolean} includeEmoji - */ -function addPercent(change, includeEmoji) { - if (!isFinite(change)) { - // When a new package is created - return 'n/a'; +function change(decimal) { + if (decimal === Infinity) { + return 'New file'; } - const formatted = (change * 100).toFixed(1); - if (/^-|^0(?:\.0+)$/.test(formatted)) { - return `${formatted}%`; - } else { - if (includeEmoji) { - return `:small_red_triangle:+${formatted}%`; - } else { - return `+${formatted}%`; - } + if (decimal === -1) { + return 'Deleted'; } -} - -function setBoldness(row, isBold) { - if (isBold) { - return row.map(element => `**${element}**`); - } else { - return row; + if (decimal < 0.0001) { + return '='; } + return percentFormatter.format(decimal); } -/** - * Gets the commit that represents the merge between the current branch - * and master. - */ -function git(args) { - return new Promise(res => { - exec('git ' + args, (err, stdout, stderr) => { - if (err) { - throw err; - } else { - res(stdout.trim()); - } - }); - }); +const header = ` + | Name | +/- | Base | Current | +/- gzip | Base gzip | Current gzip | + | ---- | --- | ---- | ------- | -------- | --------- | ------------ |`; + +function row(result, baseSha, headSha) { + const diffViewUrl = `https://react-builds.vercel.app/commits/${headSha}/files/${result.path}?compare=${baseSha}`; + const rowArr = [ + `| [${result.path}](${diffViewUrl})`, + `**${change(result.change)}**`, + `${kbs(result.baseSize)}`, + `${kbs(result.headSize)}`, + `${change(result.changeGzip)}`, + `${kbs(result.baseSizeGzip)}`, + `${kbs(result.headSizeGzip)}`, + ]; + return rowArr.join(' | '); } -(async function() { +(async function () { // Use git locally to grab the commit which represents the place // where the branches differ + const upstreamRepo = danger.github.pr.base.repo.full_name; - if (upstreamRepo !== 'facebook/react') { + if (upstreamRepo !== 'react/react') { // Exit unless we're running in the main repo return; } - markdown(`## Size changes (${RELEASE_CHANNEL})`); - - const upstreamRef = danger.github.pr.base.ref; - await git(`remote add upstream https://github.com/facebook/react.git`); - await git('fetch upstream'); - const baseCommit = await git(`merge-base HEAD upstream/${upstreamRef}`); - - let previousBuildResults = null; + let headSha; + let baseSha; try { - let baseCIBuildId = null; - const statusesResponse = await fetch( - `https://api.github.com/repos/facebook/react/commits/${baseCommit}/status` - ); - const {statuses, state} = await statusesResponse.json(); - if (state === 'failure') { - warn(`Base commit is broken: ${baseCommit}`); - return; - } - for (let i = 0; i < statuses.length; i++) { - const status = statuses[i]; - if (status.context === `ci/circleci: ${artifactsJobName}`) { - if (status.state === 'success') { - baseCIBuildId = /\/facebook\/react\/([0-9]+)/.exec( - status.target_url - )[1]; - break; - } - if (status.state === 'pending') { - warn(`Build job for base commit is still pending: ${baseCommit}`); - return; - } - } - } - - if (baseCIBuildId === null) { - warn(`Could not find build artifacts for base commit: ${baseCommit}`); - return; - } - - const baseArtifactsInfoResponse = await fetch( - `https://circleci.com/api/v1.1/project/github/facebook/react/${baseCIBuildId}/artifacts` + headSha = String(readFileSync(HEAD_DIR + '/COMMIT_SHA')).trim(); + baseSha = String(readFileSync(BASE_DIR + '/COMMIT_SHA')).trim(); + } catch { + warn( + "Failed to read build artifacts. It's possible a build configuration " + + 'has changed upstream. Try pulling the latest changes from the ' + + 'main branch.' ); - const baseArtifactsInfo = await baseArtifactsInfoResponse.json(); - - for (let i = 0; i < baseArtifactsInfo.length; i++) { - const info = baseArtifactsInfo[i]; - if (info.path.endsWith('bundle-sizes.json')) { - const resultsResponse = await fetch(info.url); - previousBuildResults = await resultsResponse.json(); - break; - } - } - } catch (error) { - warn(`Failed to fetch build artifacts for base commit: ${baseCommit}`); return; } - if (previousBuildResults === null) { - warn(`Could not find build artifacts for base commit: ${baseCommit}`); + // Disable sizeBot in a Devtools Pull Request. Because that doesn't affect production bundle size. + const commitFiles = [ + ...danger.git.created_files, + ...danger.git.deleted_files, + ...danger.git.modified_files, + ]; + if ( + commitFiles.every(filename => filename.includes('packages/react-devtools')) + ) return; + + const resultsMap = new Map(); + + // Find all the head (current) artifacts paths. + const headArtifactPaths = await glob('**/*.js', {cwd: 'build'}); + for (const artifactPath of headArtifactPaths) { + try { + // This will throw if there's no matching base artifact + const baseSize = statSync(BASE_DIR + '/' + artifactPath).size; + const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath); + + const headSize = statSync(HEAD_DIR + '/' + artifactPath).size; + const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath); + resultsMap.set(artifactPath, { + path: artifactPath, + headSize, + headSizeGzip, + baseSize, + baseSizeGzip, + change: (headSize - baseSize) / baseSize, + changeGzip: (headSizeGzip - baseSizeGzip) / baseSizeGzip, + }); + } catch { + // There's no matching base artifact. This is a new file. + const baseSize = 0; + const baseSizeGzip = 0; + const headSize = statSync(HEAD_DIR + '/' + artifactPath).size; + const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath); + resultsMap.set(artifactPath, { + path: artifactPath, + headSize, + headSizeGzip, + baseSize, + baseSizeGzip, + change: Infinity, + changeGzip: Infinity, + }); + } } - // Take the JSON of the build response and - // make an array comparing the results for printing - const results = generateResultsArray( - currentBuildResults, - previousBuildResults - ); - - const packagesToShow = results - .filter( - r => - Math.abs(r.prevFileSizeAbsoluteChange) >= 300 || // bytes - Math.abs(r.prevGzipSizeAbsoluteChange) >= 100 // bytes - ) - .map(r => r.packageName); - - if (packagesToShow.length) { - let allTables = []; - - // Highlight React and React DOM changes inline - // e.g. react: `react.production.min.js`: -3%, `react.development.js`: +4% - - if (packagesToShow.includes('react')) { - const reactProd = results.find( - r => r.bundleType === 'UMD_PROD' && r.packageName === 'react' - ); - if ( - reactProd.prevFileSizeChange !== 0 || - reactProd.prevGzipSizeChange !== 0 - ) { - const changeSize = addPercent(reactProd.prevFileSizeChange, true); - const changeGzip = addPercent(reactProd.prevGzipSizeChange, true); - markdown(`React: size: ${changeSize}, gzip: ${changeGzip}`); - } + // Check for base artifacts that were deleted in the head. + const baseArtifactPaths = await glob('**/*.js', {cwd: 'base-build'}); + for (const artifactPath of baseArtifactPaths) { + if (!resultsMap.has(artifactPath)) { + const baseSize = statSync(BASE_DIR + '/' + artifactPath).size; + const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath); + const headSize = 0; + const headSizeGzip = 0; + resultsMap.set(artifactPath, { + path: artifactPath, + headSize, + headSizeGzip, + baseSize, + baseSizeGzip, + change: -1, + changeGzip: -1, + }); } + } - if (packagesToShow.includes('react-dom')) { - const reactDOMProd = results.find( - r => r.bundleType === 'UMD_PROD' && r.packageName === 'react-dom' + const results = Array.from(resultsMap.values()); + results.sort((a, b) => b.change - a.change); + + let criticalResults = []; + for (const artifactPath of CRITICAL_ARTIFACT_PATHS) { + const result = resultsMap.get(artifactPath); + if (result === undefined) { + throw new Error( + 'Missing expected bundle. If this was an intentional change to the ' + + 'build configuration, update Dangerfile.js accordingly: ' + + artifactPath ); - if ( - reactDOMProd.prevFileSizeChange !== 0 || - reactDOMProd.prevGzipSizeChange !== 0 - ) { - const changeSize = addPercent(reactDOMProd.prevFileSizeChange, true); - const changeGzip = addPercent(reactDOMProd.prevGzipSizeChange, true); - markdown(`ReactDOM: size: ${changeSize}, gzip: ${changeGzip}`); - } } + criticalResults.push(row(result, baseSha, headSha)); + } - // Show a hidden summary table for all diffs + let significantResults = []; + for (const result of results) { + // If result exceeds critical threshold, add to top section. + if ( + (result.change > CRITICAL_THRESHOLD || + 0 - result.change > CRITICAL_THRESHOLD || + // New file + result.change === Infinity || + // Deleted file + result.change === -1) && + // Skip critical artifacts. We added those earlier, in a fixed order. + !CRITICAL_ARTIFACT_PATHS.has(result.path) + ) { + criticalResults.push(row(result, baseSha, headSha)); + } - // eslint-disable-next-line no-var,no-for-of-loops/no-for-of-loops - for (var name of new Set(packagesToShow)) { - const thisBundleResults = results.filter(r => r.packageName === name); - const changedFiles = thisBundleResults.filter( - r => r.prevFileSizeChange !== 0 || r.prevGzipSizeChange !== 0 - ); + // Do the same for results that exceed the significant threshold. These + // will go into the bottom, collapsed section. Intentionally including + // critical artifacts in this section, too. + if ( + result.change > SIGNIFICANCE_THRESHOLD || + 0 - result.change > SIGNIFICANCE_THRESHOLD || + result.change === Infinity || + result.change === -1 + ) { + significantResults.push(row(result, baseSha, headSha)); + } + } - const mdHeaders = [ - 'File', - 'Filesize Diff', - 'Gzip Diff', - 'Prev Size', - 'Current Size', - 'Prev Gzip', - 'Current Gzip', - 'ENV', - ]; - - const mdRows = changedFiles.map(r => { - const isProd = r.bundleType.includes('PROD'); - return setBoldness( - [ - r.filename, - addPercent(r.prevFileSizeChange, isProd), - addPercent(r.prevGzipSizeChange, isProd), - r.prevSize, - r.prevFileSize, - r.prevGzip, - r.prevGzipSize, - r.bundleType, - ], - isProd - ); - }); + const message = ` +Comparing: ${baseSha}...${headSha} - allTables.push(`\n## ${name}`); - allTables.push(generateMDTable(mdHeaders, mdRows)); - } +## Critical size changes - const summary = ` -
- Details of bundled changes. +Includes critical production bundles, as well as any change greater than ${ + CRITICAL_THRESHOLD * 100 + }%: -

Comparing: ${baseCommit}...${danger.github.pr.head.sha}

+${header} +${criticalResults.join('\n')} +## Significant size changes - ${allTables.join('\n')} +Includes any change greater than ${SIGNIFICANCE_THRESHOLD * 100}%: -
- `; - markdown(summary); +${ + significantResults.length > 0 + ? ` +
+Expand to show +${header} +${significantResults.join('\n')} +
+` + : '(No significant changes)' +} +`; + + // GitHub comments are limited to 65536 characters. + if (message.length > 65536) { + // Make message available as an artifact + writeFileSync('sizebot-message.md', message); + markdown( + 'The size diff is too large to display in a single comment. ' + + `The GitHub action for this pull request contains an artifact called 'sizebot-message.md' with the full message.` + ); } else { - markdown('No significant bundle size changes to report.'); + markdown(message); } })(); diff --git a/fixtures/art/VectorWidget.js b/fixtures/art/VectorWidget.js index e4a471fc2801..d6b5c3c41f69 100644 --- a/fixtures/art/VectorWidget.js +++ b/fixtures/art/VectorWidget.js @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. + * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. diff --git a/fixtures/art/package.json b/fixtures/art/package.json index 82e84bb49a4f..7bab6d59eb1c 100644 --- a/fixtures/art/package.json +++ b/fixtures/art/package.json @@ -5,12 +5,13 @@ "@babel/preset-env": "^7.10.4", "@babel/preset-react": "^7.10.4", "babel-loader": "^8.1.0", - "react": "link:../../build/node_modules/react", - "react-art": "link:../../build/node_modules/react-art/", - "react-dom": "link:../../build/node_modules/react-dom", + "react": "^19.0.0", + "react-art": "^19.0.0", + "react-dom": "^19.0.0", "webpack": "^1.14.0" }, "scripts": { + "prebuild": "cp -r ../../build/oss-experimental/* ./node_modules/", "build": "webpack app.js bundle.js" } } diff --git a/fixtures/art/yarn.lock b/fixtures/art/yarn.lock index 048ab6810318..08f99e058e05 100644 --- a/fixtures/art/yarn.lock +++ b/fixtures/art/yarn.lock @@ -1007,6 +1007,11 @@ arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" +art@^0.10.1: + version "0.10.3" + resolved "https://registry.yarnpkg.com/art/-/art-0.10.3.tgz#b01d84a968ccce6208df55a733838c96caeeaea2" + integrity sha512-HXwbdofRTiJT6qZX/FnchtldzJjS3vkLJxQilc3Xj+ma2MXjY4UAyQ0ls1XZYVnDvVIBiFZbC6QsvtW86TD6tQ== + asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" @@ -1286,6 +1291,14 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +create-react-class@^15.6.2: + version "15.7.0" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e" + integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -1761,7 +1774,7 @@ js-tokens@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -1877,15 +1890,10 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" -lodash@^4.17.13: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -lodash@^4.17.19: - version "4.17.19" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" - integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== +lodash@^4.17.13, lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== longest@^1.0.1: version "1.0.1" @@ -1897,6 +1905,13 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" +loose-envify@^1.1.0, loose-envify@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + make-dir@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -2066,9 +2081,10 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-keys@^1.0.11, object-keys@^1.0.12: version "1.1.1" @@ -2251,17 +2267,30 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -"react-art@link:../../build/node_modules/react-art": - version "0.0.0" - uid "" +react-art@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-art/-/react-art-18.2.0.tgz#73b3929b1a0ce781b088bce76186d3793f0106c5" + integrity sha512-HfSK9OBtPIpkdI4QZAyWSxCIbM/I7+nqjybxp2FLmiFS7RN+eCEvOY0KdPw+6//B1oIU31t2o35s5EEhe0Fodw== + dependencies: + art "^0.10.1" + create-react-class "^15.6.2" + loose-envify "^1.1.0" + scheduler "^0.23.0" -"react-dom@link:../../build/node_modules/react-dom": - version "0.0.0" - uid "" +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" -"react@link:../../build/node_modules/react": - version "0.0.0" - uid "" +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.2.6: version "2.2.6" @@ -2441,6 +2470,13 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + schema-utils@^2.6.5: version "2.7.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" diff --git a/fixtures/attribute-behavior/AttributeTableSnapshot.md b/fixtures/attribute-behavior/AttributeTableSnapshot.md index 5a57877f1b64..004a35db8d40 100644 --- a/fixtures/attribute-behavior/AttributeTableSnapshot.md +++ b/fixtures/attribute-behavior/AttributeTableSnapshot.md @@ -294,7 +294,7 @@ | `action=(string 'on')`| (changed)| `"http://localhost:3000/on"` | | `action=(string 'off')`| (changed)| `"http://localhost:3000/off"` | | `action=(symbol)`| (initial, warning)| `"http://localhost:3000/"` | -| `action=(function)`| (initial, warning)| `"http://localhost:3000/"` | +| `action=(function)`| (changed, ssr error, ssr mismatch)| `"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')"` | | `action=(null)`| (initial)| `"http://localhost:3000/"` | | `action=(undefined)`| (initial)| `"http://localhost:3000/"` | @@ -526,23 +526,23 @@ ## `amplitude` (on `` inside ``) | Test Case | Flags | Result | | --- | --- | --- | -| `amplitude=(string)`| (changed)| `` | +| `amplitude=(string)`| (initial)| `` | | `amplitude=(empty string)`| (changed)| `` | -| `amplitude=(array with string)`| (changed)| `` | +| `amplitude=(array with string)`| (initial)| `` | | `amplitude=(empty array)`| (changed)| `` | -| `amplitude=(object)`| (changed)| `` | +| `amplitude=(object)`| (initial)| `` | | `amplitude=(numeric string)`| (changed)| `` | | `amplitude=(-1)`| (changed)| `` | | `amplitude=(0)`| (changed)| `` | | `amplitude=(integer)`| (initial)| `` | -| `amplitude=(NaN)`| (changed, warning)| `` | +| `amplitude=(NaN)`| (initial, warning)| `` | | `amplitude=(float)`| (changed)| `` | | `amplitude=(true)`| (initial, warning)| `` | | `amplitude=(false)`| (initial, warning)| `` | -| `amplitude=(string 'true')`| (changed)| `` | -| `amplitude=(string 'false')`| (changed)| `` | -| `amplitude=(string 'on')`| (changed)| `` | -| `amplitude=(string 'off')`| (changed)| `` | +| `amplitude=(string 'true')`| (initial)| `` | +| `amplitude=(string 'false')`| (initial)| `` | +| `amplitude=(string 'on')`| (initial)| `` | +| `amplitude=(string 'off')`| (initial)| `` | | `amplitude=(symbol)`| (initial, warning)| `` | | `amplitude=(function)`| (initial, warning)| `` | | `amplitude=(null)`| (initial)| `` | @@ -648,6 +648,31 @@ | `aria-=(null)`| (initial, warning)| `` | | `aria-=(undefined)`| (initial, warning)| `` | +## `aria-hidden` (on `
` inside `
`) +| Test Case | Flags | Result | +| --- | --- | --- | +| `aria-hidden=(string)`| (changed)| `"a string"` | +| `aria-hidden=(empty string)`| (changed)| `` | +| `aria-hidden=(array with string)`| (changed)| `"string"` | +| `aria-hidden=(empty array)`| (changed)| `` | +| `aria-hidden=(object)`| (changed)| `"result of toString()"` | +| `aria-hidden=(numeric string)`| (changed)| `"42"` | +| `aria-hidden=(-1)`| (changed)| `"-1"` | +| `aria-hidden=(0)`| (changed)| `"0"` | +| `aria-hidden=(integer)`| (changed)| `"1"` | +| `aria-hidden=(NaN)`| (changed)| `"NaN"` | +| `aria-hidden=(float)`| (changed)| `"99.99"` | +| `aria-hidden=(true)`| (changed)| `"true"` | +| `aria-hidden=(false)`| (changed)| `"false"` | +| `aria-hidden=(string 'true')`| (changed)| `"true"` | +| `aria-hidden=(string 'false')`| (changed)| `"false"` | +| `aria-hidden=(string 'on')`| (changed)| `"on"` | +| `aria-hidden=(string 'off')`| (changed)| `"off"` | +| `aria-hidden=(symbol)`| (initial)| `` | +| `aria-hidden=(function)`| (initial)| `` | +| `aria-hidden=(null)`| (initial)| `` | +| `aria-hidden=(undefined)`| (initial)| `` | + ## `aria-invalidattribute` (on `
` inside `
`) | Test Case | Flags | Result | | --- | --- | --- | @@ -830,17 +855,17 @@ | `autoComplete=(empty string)`| (initial)| `` | | `autoComplete=(array with string)`| (changed)| `"email"` | | `autoComplete=(empty array)`| (initial)| `` | -| `autoComplete=(object)`| (changed)| `"result of toString()"` | -| `autoComplete=(numeric string)`| (changed)| `"42"` | -| `autoComplete=(-1)`| (changed)| `"-1"` | -| `autoComplete=(0)`| (changed)| `"0"` | -| `autoComplete=(integer)`| (changed)| `"1"` | -| `autoComplete=(NaN)`| (changed, warning)| `"NaN"` | -| `autoComplete=(float)`| (changed)| `"99.99"` | +| `autoComplete=(object)`| (initial)| `` | +| `autoComplete=(numeric string)`| (initial)| `` | +| `autoComplete=(-1)`| (initial)| `` | +| `autoComplete=(0)`| (initial)| `` | +| `autoComplete=(integer)`| (initial)| `` | +| `autoComplete=(NaN)`| (initial, warning)| `` | +| `autoComplete=(float)`| (initial)| `` | | `autoComplete=(true)`| (initial, warning)| `` | | `autoComplete=(false)`| (initial, warning)| `` | -| `autoComplete=(string 'true')`| (changed)| `"true"` | -| `autoComplete=(string 'false')`| (changed)| `"false"` | +| `autoComplete=(string 'true')`| (initial)| `` | +| `autoComplete=(string 'false')`| (initial)| `` | | `autoComplete=(string 'on')`| (changed)| `"on"` | | `autoComplete=(string 'off')`| (changed)| `"off"` | | `autoComplete=(symbol)`| (initial, warning)| `` | @@ -1469,16 +1494,16 @@ | `children=(string 'on')`| (initial)| `[]` | | `children=(string 'off')`| (initial)| `[]` | | `children=(symbol)`| (initial)| `[]` | -| `children=(function)`| (initial, warning, ssr warning)| `[]` | +| `children=(function)`| (initial, warning)| `[]` | | `children=(null)`| (initial)| `[]` | | `children=(undefined)`| (initial)| `[]` | ## `cite` (on `
` inside `
`) | Test Case | Flags | Result | | --- | --- | --- | -| `cite=(string)`| (changed)| `"http://reactjs.com/"` | +| `cite=(string)`| (changed)| `"https://reactjs.com/"` | | `cite=(empty string)`| (changed)| `"http://localhost:3000/"` | -| `cite=(array with string)`| (changed)| `"http://reactjs.com/"` | +| `cite=(array with string)`| (changed)| `"https://reactjs.com/"` | | `cite=(empty array)`| (changed)| `"http://localhost:3000/"` | | `cite=(object)`| (changed)| `"http://localhost:3000/result%20of%20toString()"` | | `cite=(numeric string)`| (changed)| `"http://localhost:3000/42"` | @@ -1998,7 +2023,7 @@ | `colSpan=(null)`| (initial, ssr error, ssr mismatch)| `` | | `colSpan=(undefined)`| (initial, ssr error, ssr mismatch)| `` | -## `content` (on `` inside `
`) +## `content` (on `` inside ``) | Test Case | Flags | Result | | --- | --- | --- | | `content=(string)`| (changed)| `"a string"` | @@ -2560,7 +2585,7 @@ | `defaultChecked=(-1)`| (changed)| `` | | `defaultChecked=(0)`| (initial)| `` | | `defaultChecked=(integer)`| (changed)| `` | -| `defaultChecked=(NaN)`| (initial, warning, ssr warning)| `` | +| `defaultChecked=(NaN)`| (initial, warning)| `` | | `defaultChecked=(float)`| (changed)| `` | | `defaultChecked=(true)`| (changed)| `` | | `defaultChecked=(false)`| (initial)| `` | @@ -2568,8 +2593,8 @@ | `defaultChecked=(string 'false')`| (changed)| `` | | `defaultChecked=(string 'on')`| (changed)| `` | | `defaultChecked=(string 'off')`| (changed)| `` | -| `defaultChecked=(symbol)`| (changed, ssr mismatch)| `` | -| `defaultChecked=(function)`| (changed, ssr mismatch)| `` | +| `defaultChecked=(symbol)`| (initial)| `` | +| `defaultChecked=(function)`| (initial)| `` | | `defaultChecked=(null)`| (initial)| `` | | `defaultChecked=(undefined)`| (initial)| `` | @@ -2593,9 +2618,9 @@ | `defaultValue=(string 'false')`| (changed)| `"false"` | | `defaultValue=(string 'on')`| (changed)| `"on"` | | `defaultValue=(string 'off')`| (changed)| `"off"` | -| `defaultValue=(symbol)`| (initial, ssr warning)| `` | -| `defaultValue=(function)`| (initial, ssr warning)| `` | -| `defaultValue=(null)`| (initial, ssr warning)| `` | +| `defaultValue=(symbol)`| (initial)| `` | +| `defaultValue=(function)`| (initial)| `` | +| `defaultValue=(null)`| (initial)| `` | | `defaultValue=(undefined)`| (initial)| `` | ## `defaultValuE` (on `` inside `
`) @@ -2676,23 +2701,23 @@ ## `diffuseConstant` (on `` inside ``) | Test Case | Flags | Result | | --- | --- | --- | -| `diffuseConstant=(string)`| (changed)| `` | +| `diffuseConstant=(string)`| (initial)| `` | | `diffuseConstant=(empty string)`| (changed)| `` | -| `diffuseConstant=(array with string)`| (changed)| `` | +| `diffuseConstant=(array with string)`| (initial)| `` | | `diffuseConstant=(empty array)`| (changed)| `` | -| `diffuseConstant=(object)`| (changed)| `` | +| `diffuseConstant=(object)`| (initial)| `` | | `diffuseConstant=(numeric string)`| (changed)| `` | | `diffuseConstant=(-1)`| (changed)| `` | | `diffuseConstant=(0)`| (changed)| `` | | `diffuseConstant=(integer)`| (initial)| `` | -| `diffuseConstant=(NaN)`| (changed, warning)| `` | +| `diffuseConstant=(NaN)`| (initial, warning)| `` | | `diffuseConstant=(float)`| (changed)| `` | | `diffuseConstant=(true)`| (initial, warning)| `` | | `diffuseConstant=(false)`| (initial, warning)| `` | -| `diffuseConstant=(string 'true')`| (changed)| `` | -| `diffuseConstant=(string 'false')`| (changed)| `` | -| `diffuseConstant=(string 'on')`| (changed)| `` | -| `diffuseConstant=(string 'off')`| (changed)| `` | +| `diffuseConstant=(string 'true')`| (initial)| `` | +| `diffuseConstant=(string 'false')`| (initial)| `` | +| `diffuseConstant=(string 'on')`| (initial)| `` | +| `diffuseConstant=(string 'off')`| (initial)| `` | | `diffuseConstant=(symbol)`| (initial, warning)| `` | | `diffuseConstant=(function)`| (initial, warning)| `` | | `diffuseConstant=(null)`| (initial)| `` | @@ -2773,6 +2798,56 @@ | `disabled=(null)`| (initial)| `` | | `disabled=(undefined)`| (initial)| `` | +## `disablePictureInPicture` (on `
`) +| Test Case | Flags | Result | +| --- | --- | --- | +| `disablePictureInPicture=(string)`| (initial)| `` | +| `disablePictureInPicture=(empty string)`| (initial)| `` | +| `disablePictureInPicture=(array with string)`| (initial)| `` | +| `disablePictureInPicture=(empty array)`| (initial)| `` | +| `disablePictureInPicture=(object)`| (initial)| `` | +| `disablePictureInPicture=(numeric string)`| (initial)| `` | +| `disablePictureInPicture=(-1)`| (initial)| `` | +| `disablePictureInPicture=(0)`| (initial)| `` | +| `disablePictureInPicture=(integer)`| (initial)| `` | +| `disablePictureInPicture=(NaN)`| (initial, warning)| `` | +| `disablePictureInPicture=(float)`| (initial)| `` | +| `disablePictureInPicture=(true)`| (initial)| `` | +| `disablePictureInPicture=(false)`| (initial)| `` | +| `disablePictureInPicture=(string 'true')`| (initial, warning)| `` | +| `disablePictureInPicture=(string 'false')`| (initial, warning)| `` | +| `disablePictureInPicture=(string 'on')`| (initial)| `` | +| `disablePictureInPicture=(string 'off')`| (initial)| `` | +| `disablePictureInPicture=(symbol)`| (initial, warning)| `` | +| `disablePictureInPicture=(function)`| (initial, warning)| `` | +| `disablePictureInPicture=(null)`| (initial)| `` | +| `disablePictureInPicture=(undefined)`| (initial)| `` | + +## `disableRemotePlayback` (on `